1d9f0492fSopenharmony_ci/*
2d9f0492fSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3d9f0492fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4d9f0492fSopenharmony_ci * you may not use this file except in compliance with the License.
5d9f0492fSopenharmony_ci * You may obtain a copy of the License at
6d9f0492fSopenharmony_ci *
7d9f0492fSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8d9f0492fSopenharmony_ci *
9d9f0492fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10d9f0492fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11d9f0492fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12d9f0492fSopenharmony_ci * See the License for the specific language governing permissions and
13d9f0492fSopenharmony_ci * limitations under the License.
14d9f0492fSopenharmony_ci */
15d9f0492fSopenharmony_ci
16d9f0492fSopenharmony_ci#include <ctype.h>
17d9f0492fSopenharmony_ci#include <libgen.h>
18d9f0492fSopenharmony_ci#include <limits.h>
19d9f0492fSopenharmony_ci#include <stdio.h>
20d9f0492fSopenharmony_ci#include <string.h>
21d9f0492fSopenharmony_ci#include <stdbool.h>
22d9f0492fSopenharmony_ci#include <sys/mount.h>
23d9f0492fSopenharmony_ci#include <sys/types.h>
24d9f0492fSopenharmony_ci#include "beget_ext.h"
25d9f0492fSopenharmony_ci#include "fs_manager/fs_manager.h"
26d9f0492fSopenharmony_ci#include "init_utils.h"
27d9f0492fSopenharmony_ci#include "securec.h"
28d9f0492fSopenharmony_ci
29d9f0492fSopenharmony_ci#ifdef __cplusplus
30d9f0492fSopenharmony_ci#if __cplusplus
31d9f0492fSopenharmony_ciextern "C" {
32d9f0492fSopenharmony_ci#endif
33d9f0492fSopenharmony_ci#endif
34d9f0492fSopenharmony_ci
35d9f0492fSopenharmony_ci#define CMDLINE_LABEL_FSCRYPT_DISABLE  "ohos.init.fscrypt.disable"
36d9f0492fSopenharmony_ci#define CMDLINE_VALUE_FSCRYPT_DISABLE  "disabled"
37d9f0492fSopenharmony_ci#define CMDLINE_VALUE_LEN              (sizeof(CMDLINE_VALUE_FSCRYPT_DISABLE) - 1)
38d9f0492fSopenharmony_cistruct FsManagerFlags {
39d9f0492fSopenharmony_ci    char *name;
40d9f0492fSopenharmony_ci    unsigned int flags;
41d9f0492fSopenharmony_ci};
42d9f0492fSopenharmony_ci
43d9f0492fSopenharmony_cistruct MountFlags {
44d9f0492fSopenharmony_ci    char *name;
45d9f0492fSopenharmony_ci    unsigned long flags;
46d9f0492fSopenharmony_ci};
47d9f0492fSopenharmony_ci
48d9f0492fSopenharmony_cistatic char *g_fscryptPolicy = NULL;
49d9f0492fSopenharmony_ci
50d9f0492fSopenharmony_cistatic unsigned int ConvertFlags(char *flagBuffer)
51d9f0492fSopenharmony_ci{
52d9f0492fSopenharmony_ci    static struct FsManagerFlags fsFlags[] = {
53d9f0492fSopenharmony_ci        {"check", FS_MANAGER_CHECK},
54d9f0492fSopenharmony_ci        {"wait", FS_MANAGER_WAIT},
55d9f0492fSopenharmony_ci        {"required", FS_MANAGER_REQUIRED},
56d9f0492fSopenharmony_ci        {"nofail", FS_MANAGER_NOFAIL},
57d9f0492fSopenharmony_ci#ifdef SUPPORT_HVB
58d9f0492fSopenharmony_ci        {"hvb", FS_MANAGER_HVB},
59d9f0492fSopenharmony_ci#endif
60d9f0492fSopenharmony_ci        {"fsprojquota", FS_MANAGER_PROJQUOTA},
61d9f0492fSopenharmony_ci        {"fscasefold", FS_MANAGER_CASEFOLD},
62d9f0492fSopenharmony_ci        {"fscompression", FS_MANAGER_COMPRESSION},
63d9f0492fSopenharmony_ci        {"fsdedup", FS_MANAGER_DEDUP},
64d9f0492fSopenharmony_ci        {"formattable", FS_MANAGER_FORMATTABLE},
65d9f0492fSopenharmony_ci    };
66d9f0492fSopenharmony_ci
67d9f0492fSopenharmony_ci    BEGET_CHECK_RETURN_VALUE(flagBuffer != NULL && *flagBuffer != '\0', 0); // No valid flags.
68d9f0492fSopenharmony_ci    int flagCount = 0;
69d9f0492fSopenharmony_ci    unsigned int flags = 0;
70d9f0492fSopenharmony_ci    const int maxCount = 3;
71d9f0492fSopenharmony_ci    char **vector = SplitStringExt(flagBuffer, ",", &flagCount, maxCount);
72d9f0492fSopenharmony_ci    BEGET_CHECK_RETURN_VALUE(vector != NULL && flagCount != 0, 0);
73d9f0492fSopenharmony_ci    for (size_t i = 0; i < ARRAY_LENGTH(fsFlags); i++) {
74d9f0492fSopenharmony_ci        for (int j = 0; j < flagCount; j++) {
75d9f0492fSopenharmony_ci            if (strcmp(fsFlags[i].name, vector[j]) == 0) {
76d9f0492fSopenharmony_ci                flags |= fsFlags[i].flags;
77d9f0492fSopenharmony_ci            }
78d9f0492fSopenharmony_ci        }
79d9f0492fSopenharmony_ci    }
80d9f0492fSopenharmony_ci    FreeStringVector(vector, flagCount);
81d9f0492fSopenharmony_ci    return flags;
82d9f0492fSopenharmony_ci}
83d9f0492fSopenharmony_ci
84d9f0492fSopenharmony_cistatic int AddToFstab(Fstab *fstab, FstabItem *item)
85d9f0492fSopenharmony_ci{
86d9f0492fSopenharmony_ci    if (fstab == NULL || item == NULL) {
87d9f0492fSopenharmony_ci        return -1;
88d9f0492fSopenharmony_ci    }
89d9f0492fSopenharmony_ci    if (fstab->tail == NULL) {
90d9f0492fSopenharmony_ci        fstab->head = fstab->tail = item;
91d9f0492fSopenharmony_ci    } else {
92d9f0492fSopenharmony_ci        fstab->tail->next = item;
93d9f0492fSopenharmony_ci        fstab->tail = item;
94d9f0492fSopenharmony_ci    }
95d9f0492fSopenharmony_ci    return 0;
96d9f0492fSopenharmony_ci}
97d9f0492fSopenharmony_ci
98d9f0492fSopenharmony_civoid ReleaseFstabItem(FstabItem *item)
99d9f0492fSopenharmony_ci{
100d9f0492fSopenharmony_ci    if (item != NULL) {
101d9f0492fSopenharmony_ci        if (item->deviceName != NULL) {
102d9f0492fSopenharmony_ci            free(item->deviceName);
103d9f0492fSopenharmony_ci            item->deviceName = NULL;
104d9f0492fSopenharmony_ci        }
105d9f0492fSopenharmony_ci
106d9f0492fSopenharmony_ci        if (item->mountPoint != NULL) {
107d9f0492fSopenharmony_ci            free(item->mountPoint);
108d9f0492fSopenharmony_ci            item->mountPoint = NULL;
109d9f0492fSopenharmony_ci        }
110d9f0492fSopenharmony_ci
111d9f0492fSopenharmony_ci        if (item->fsType != NULL) {
112d9f0492fSopenharmony_ci            free(item->fsType);
113d9f0492fSopenharmony_ci            item->fsType = NULL;
114d9f0492fSopenharmony_ci        }
115d9f0492fSopenharmony_ci
116d9f0492fSopenharmony_ci        if (item->mountOptions != NULL) {
117d9f0492fSopenharmony_ci            free(item->mountOptions);
118d9f0492fSopenharmony_ci            item->mountOptions = NULL;
119d9f0492fSopenharmony_ci        }
120d9f0492fSopenharmony_ci
121d9f0492fSopenharmony_ci        free(item);
122d9f0492fSopenharmony_ci    }
123d9f0492fSopenharmony_ci}
124d9f0492fSopenharmony_ci
125d9f0492fSopenharmony_civoid ReleaseFstab(Fstab *fstab)
126d9f0492fSopenharmony_ci{
127d9f0492fSopenharmony_ci    if (fstab != NULL) {
128d9f0492fSopenharmony_ci        FstabItem *item = fstab->head;
129d9f0492fSopenharmony_ci        while (item != NULL) {
130d9f0492fSopenharmony_ci            FstabItem *tmp = item->next;
131d9f0492fSopenharmony_ci            ReleaseFstabItem(item);
132d9f0492fSopenharmony_ci            item = tmp;
133d9f0492fSopenharmony_ci        }
134d9f0492fSopenharmony_ci        fstab->head = fstab->tail = NULL;
135d9f0492fSopenharmony_ci        free(fstab);
136d9f0492fSopenharmony_ci        fstab = NULL;
137d9f0492fSopenharmony_ci    }
138d9f0492fSopenharmony_ci}
139d9f0492fSopenharmony_ci
140d9f0492fSopenharmony_ciint ParseFstabPerLine(char *str, Fstab *fstab, bool procMounts, const char *separator)
141d9f0492fSopenharmony_ci{
142d9f0492fSopenharmony_ci    BEGET_CHECK_RETURN_VALUE(str != NULL && fstab != NULL, -1);
143d9f0492fSopenharmony_ci    char *rest = NULL;
144d9f0492fSopenharmony_ci    FstabItem *item = NULL;
145d9f0492fSopenharmony_ci    char *p = NULL;
146d9f0492fSopenharmony_ci    BEGET_ERROR_CHECK(separator != NULL && *separator != '\0', return -1, "Invalid separator for parsing fstab");
147d9f0492fSopenharmony_ci
148d9f0492fSopenharmony_ci    if ((item = (FstabItem *)calloc(1, sizeof(FstabItem))) == NULL) {
149d9f0492fSopenharmony_ci        errno = ENOMEM;
150d9f0492fSopenharmony_ci        BEGET_LOGE("Allocate memory for FS table item failed, err = %d", errno);
151d9f0492fSopenharmony_ci        return -1;
152d9f0492fSopenharmony_ci    }
153d9f0492fSopenharmony_ci
154d9f0492fSopenharmony_ci    do {
155d9f0492fSopenharmony_ci        BEGET_ERROR_CHECK((p = strtok_r(str, separator, &rest)) != NULL, break, "Failed to parse block device.");
156d9f0492fSopenharmony_ci        item->deviceName = strdup(p);
157d9f0492fSopenharmony_ci        BEGET_ERROR_CHECK(item->deviceName != NULL, break, "strdup deviceName failed.");
158d9f0492fSopenharmony_ci
159d9f0492fSopenharmony_ci        BEGET_ERROR_CHECK((p = strtok_r(NULL, separator, &rest)) != NULL, break, "Failed to parse mount point.");
160d9f0492fSopenharmony_ci        item->mountPoint = strdup(p);
161d9f0492fSopenharmony_ci        BEGET_ERROR_CHECK(item->mountPoint != NULL, break, "strdup mountPoint failed.");
162d9f0492fSopenharmony_ci
163d9f0492fSopenharmony_ci        BEGET_ERROR_CHECK((p = strtok_r(NULL, separator, &rest)) != NULL, break, "Failed to parse fs type.");
164d9f0492fSopenharmony_ci        item->fsType = strdup(p);
165d9f0492fSopenharmony_ci        BEGET_ERROR_CHECK(item->fsType != NULL, break, "strdup fsType failed.");
166d9f0492fSopenharmony_ci
167d9f0492fSopenharmony_ci        BEGET_ERROR_CHECK((p = strtok_r(NULL, separator, &rest)) != NULL, break, "Failed to parse mount options.");
168d9f0492fSopenharmony_ci        item->mountOptions = strdup(p);
169d9f0492fSopenharmony_ci        BEGET_ERROR_CHECK(item->mountOptions != NULL, break, "strdup mountOptions failed.");
170d9f0492fSopenharmony_ci
171d9f0492fSopenharmony_ci        if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
172d9f0492fSopenharmony_ci            BEGET_LOGE("Failed to parse fs manager flags.");
173d9f0492fSopenharmony_ci            break;
174d9f0492fSopenharmony_ci        }
175d9f0492fSopenharmony_ci        // @fsManagerFlags only for fstab
176d9f0492fSopenharmony_ci        // Ignore it if we read from /proc/mounts
177d9f0492fSopenharmony_ci        if (!procMounts) {
178d9f0492fSopenharmony_ci            item->fsManagerFlags = ConvertFlags(p);
179d9f0492fSopenharmony_ci        } else {
180d9f0492fSopenharmony_ci            item->fsManagerFlags = 0;
181d9f0492fSopenharmony_ci        }
182d9f0492fSopenharmony_ci        return AddToFstab(fstab, item);
183d9f0492fSopenharmony_ci    } while (0);
184d9f0492fSopenharmony_ci
185d9f0492fSopenharmony_ci    ReleaseFstabItem(item);
186d9f0492fSopenharmony_ci    item = NULL;
187d9f0492fSopenharmony_ci    return -1;
188d9f0492fSopenharmony_ci}
189d9f0492fSopenharmony_ci
190d9f0492fSopenharmony_ciFstab *ReadFstabFromFile(const char *file, bool procMounts)
191d9f0492fSopenharmony_ci{
192d9f0492fSopenharmony_ci    char *line = NULL;
193d9f0492fSopenharmony_ci    size_t allocn = 0;
194d9f0492fSopenharmony_ci    ssize_t readn = 0;
195d9f0492fSopenharmony_ci    Fstab *fstab = NULL;
196d9f0492fSopenharmony_ci
197d9f0492fSopenharmony_ci    FILE *fp = NULL;
198d9f0492fSopenharmony_ci    char *realPath = GetRealPath(file);
199d9f0492fSopenharmony_ci    if (realPath != NULL) {
200d9f0492fSopenharmony_ci        fp = fopen(realPath, "r");
201d9f0492fSopenharmony_ci        free(realPath);
202d9f0492fSopenharmony_ci    } else {
203d9f0492fSopenharmony_ci        fp = fopen(file, "r"); // no file system, can not get real path
204d9f0492fSopenharmony_ci    }
205d9f0492fSopenharmony_ci    BEGET_ERROR_CHECK(fp != NULL, return NULL, "Open %s failed, err = %d", file, errno);
206d9f0492fSopenharmony_ci
207d9f0492fSopenharmony_ci    if ((fstab = (Fstab *)calloc(1, sizeof(Fstab))) == NULL) {
208d9f0492fSopenharmony_ci        BEGET_LOGE("Allocate memory for FS table failed, err = %d", errno);
209d9f0492fSopenharmony_ci        fclose(fp);
210d9f0492fSopenharmony_ci        fp = NULL;
211d9f0492fSopenharmony_ci        return NULL;
212d9f0492fSopenharmony_ci    }
213d9f0492fSopenharmony_ci
214d9f0492fSopenharmony_ci    // Record line number of fstab file
215d9f0492fSopenharmony_ci    size_t ln = 0;
216d9f0492fSopenharmony_ci    while ((readn = getline(&line, &allocn, fp)) != -1) {
217d9f0492fSopenharmony_ci        char *p = NULL;
218d9f0492fSopenharmony_ci        ln++;
219d9f0492fSopenharmony_ci        if (line[readn - 1] == '\n') {
220d9f0492fSopenharmony_ci            line[readn - 1] = '\0';
221d9f0492fSopenharmony_ci        }
222d9f0492fSopenharmony_ci        p = line;
223d9f0492fSopenharmony_ci        while (isspace(*p)) {
224d9f0492fSopenharmony_ci            p++;
225d9f0492fSopenharmony_ci        }
226d9f0492fSopenharmony_ci
227d9f0492fSopenharmony_ci        if (*p == '\0' || *p == '#') {
228d9f0492fSopenharmony_ci            continue;
229d9f0492fSopenharmony_ci        }
230d9f0492fSopenharmony_ci
231d9f0492fSopenharmony_ci        if (ParseFstabPerLine(p, fstab, procMounts, " \t") < 0) {
232d9f0492fSopenharmony_ci            if (errno == ENOMEM) {
233d9f0492fSopenharmony_ci                // Ran out of memory, there is no reason to continue.
234d9f0492fSopenharmony_ci                break;
235d9f0492fSopenharmony_ci            }
236d9f0492fSopenharmony_ci            // If one line in fstab file parsed with a failure. just give a warning
237d9f0492fSopenharmony_ci            // and skip it.
238d9f0492fSopenharmony_ci            BEGET_LOGW("Cannot parse file \" %s \" at line %zu. skip it", file, ln);
239d9f0492fSopenharmony_ci            continue;
240d9f0492fSopenharmony_ci        }
241d9f0492fSopenharmony_ci    }
242d9f0492fSopenharmony_ci    if (line != NULL) {
243d9f0492fSopenharmony_ci        free(line);
244d9f0492fSopenharmony_ci    }
245d9f0492fSopenharmony_ci    (void)fclose(fp);
246d9f0492fSopenharmony_ci    fp = NULL;
247d9f0492fSopenharmony_ci    return fstab;
248d9f0492fSopenharmony_ci}
249d9f0492fSopenharmony_ci
250d9f0492fSopenharmony_ciFstabItem *FindFstabItemForMountPoint(Fstab fstab, const char *mp)
251d9f0492fSopenharmony_ci{
252d9f0492fSopenharmony_ci    FstabItem *item = NULL;
253d9f0492fSopenharmony_ci    if (mp != NULL) {
254d9f0492fSopenharmony_ci        for (item = fstab.head; item != NULL; item = item->next) {
255d9f0492fSopenharmony_ci            if ((item->mountPoint != NULL) && (strcmp(item->mountPoint, mp) == 0)) {
256d9f0492fSopenharmony_ci                break;
257d9f0492fSopenharmony_ci            }
258d9f0492fSopenharmony_ci        }
259d9f0492fSopenharmony_ci    }
260d9f0492fSopenharmony_ci    return item;
261d9f0492fSopenharmony_ci}
262d9f0492fSopenharmony_ci
263d9f0492fSopenharmony_ciFstabItem *FindFstabItemForPath(Fstab fstab, const char *path)
264d9f0492fSopenharmony_ci{
265d9f0492fSopenharmony_ci    FstabItem *item = NULL;
266d9f0492fSopenharmony_ci
267d9f0492fSopenharmony_ci    if (path == NULL || *path != '/') {
268d9f0492fSopenharmony_ci        return NULL;
269d9f0492fSopenharmony_ci    }
270d9f0492fSopenharmony_ci
271d9f0492fSopenharmony_ci    char tmp[PATH_MAX] = {0};
272d9f0492fSopenharmony_ci    char *dir = NULL;
273d9f0492fSopenharmony_ci    if (strncpy_s(tmp, PATH_MAX - 1,  path, strlen(path)) != EOK) {
274d9f0492fSopenharmony_ci        BEGET_LOGE("Failed to copy path.");
275d9f0492fSopenharmony_ci        return NULL;
276d9f0492fSopenharmony_ci    }
277d9f0492fSopenharmony_ci
278d9f0492fSopenharmony_ci    dir = tmp;
279d9f0492fSopenharmony_ci    while (true) {
280d9f0492fSopenharmony_ci        item = FindFstabItemForMountPoint(fstab, dir);
281d9f0492fSopenharmony_ci        if (item != NULL) {
282d9f0492fSopenharmony_ci            break;
283d9f0492fSopenharmony_ci        }
284d9f0492fSopenharmony_ci        dir = dirname(dir);
285d9f0492fSopenharmony_ci        // Reverse walk through path and met "/", just quit.
286d9f0492fSopenharmony_ci        if (dir == NULL || strcmp(dir, "/") == 0) {
287d9f0492fSopenharmony_ci            break;
288d9f0492fSopenharmony_ci        }
289d9f0492fSopenharmony_ci    }
290d9f0492fSopenharmony_ci    return item;
291d9f0492fSopenharmony_ci}
292d9f0492fSopenharmony_ci
293d9f0492fSopenharmony_cistatic char *GetFstabFile(char *fileName, size_t size)
294d9f0492fSopenharmony_ci{
295d9f0492fSopenharmony_ci    if (InUpdaterMode() == 1) {
296d9f0492fSopenharmony_ci        if (strncpy_s(fileName, size, "/etc/fstab.updater", strlen("/etc/fstab.updater")) != 0) {
297d9f0492fSopenharmony_ci            BEGET_LOGE("Failed strncpy_s err=%d", errno);
298d9f0492fSopenharmony_ci            return NULL;
299d9f0492fSopenharmony_ci        }
300d9f0492fSopenharmony_ci    } else {
301d9f0492fSopenharmony_ci        char hardware[MAX_BUFFER_LEN] = {0};
302d9f0492fSopenharmony_ci        int ret = GetParameterFromCmdLine("hardware", hardware, MAX_BUFFER_LEN);
303d9f0492fSopenharmony_ci        if (ret != 0) {
304d9f0492fSopenharmony_ci            BEGET_LOGE("Failed get hardware from cmdline");
305d9f0492fSopenharmony_ci            return NULL;
306d9f0492fSopenharmony_ci        }
307d9f0492fSopenharmony_ci        if (snprintf_s(fileName, size, size - 1, "/vendor/etc/fstab.%s", hardware) == -1) {
308d9f0492fSopenharmony_ci            BEGET_LOGE("Failed to build fstab file, err=%d", errno);
309d9f0492fSopenharmony_ci            return NULL;
310d9f0492fSopenharmony_ci        }
311d9f0492fSopenharmony_ci    }
312d9f0492fSopenharmony_ci    BEGET_LOGI("fstab file is %s", fileName);
313d9f0492fSopenharmony_ci    return fileName;
314d9f0492fSopenharmony_ci}
315d9f0492fSopenharmony_ci
316d9f0492fSopenharmony_ciint GetBlockDeviceByMountPoint(const char *mountPoint, const Fstab *fstab, char *deviceName, int nameLen)
317d9f0492fSopenharmony_ci{
318d9f0492fSopenharmony_ci    if (fstab == NULL || mountPoint == NULL || *mountPoint == '\0' || deviceName == NULL) {
319d9f0492fSopenharmony_ci        return -1;
320d9f0492fSopenharmony_ci    }
321d9f0492fSopenharmony_ci    FstabItem *item = FindFstabItemForMountPoint(*fstab, mountPoint);
322d9f0492fSopenharmony_ci    if (item == NULL) {
323d9f0492fSopenharmony_ci        BEGET_LOGE("Failed to get fstab item from mount point \" %s \"", mountPoint);
324d9f0492fSopenharmony_ci        return -1;
325d9f0492fSopenharmony_ci    }
326d9f0492fSopenharmony_ci    if (strncpy_s(deviceName, nameLen, item->deviceName, strlen(item->deviceName)) != 0) {
327d9f0492fSopenharmony_ci        BEGET_LOGE("Failed to copy block device name, err=%d", errno);
328d9f0492fSopenharmony_ci        return -1;
329d9f0492fSopenharmony_ci    }
330d9f0492fSopenharmony_ci    return 0;
331d9f0492fSopenharmony_ci}
332d9f0492fSopenharmony_ci
333d9f0492fSopenharmony_ciint GetBlockDeviceByName(const char *deviceName, const Fstab *fstab, char* miscDev, size_t size)
334d9f0492fSopenharmony_ci{
335d9f0492fSopenharmony_ci    for (FstabItem *item = fstab->head; item != NULL; item = item->next) {
336d9f0492fSopenharmony_ci        if (strstr(item->deviceName, deviceName) != NULL) {
337d9f0492fSopenharmony_ci            BEGET_CHECK_RETURN_VALUE(strcpy_s(miscDev, size, item->deviceName) != 0, 0);
338d9f0492fSopenharmony_ci        }
339d9f0492fSopenharmony_ci    }
340d9f0492fSopenharmony_ci    return -1;
341d9f0492fSopenharmony_ci}
342d9f0492fSopenharmony_ci
343d9f0492fSopenharmony_cistatic const struct MountFlags MOUNT_FLAGS[] = {
344d9f0492fSopenharmony_ci    { "noatime", MS_NOATIME },
345d9f0492fSopenharmony_ci    { "noexec", MS_NOEXEC },
346d9f0492fSopenharmony_ci    { "nosuid", MS_NOSUID },
347d9f0492fSopenharmony_ci    { "nodev", MS_NODEV },
348d9f0492fSopenharmony_ci    { "nodiratime", MS_NODIRATIME },
349d9f0492fSopenharmony_ci    { "ro", MS_RDONLY },
350d9f0492fSopenharmony_ci    { "rw", 0 },
351d9f0492fSopenharmony_ci    { "sync", MS_SYNCHRONOUS },
352d9f0492fSopenharmony_ci    { "remount", MS_REMOUNT },
353d9f0492fSopenharmony_ci    { "bind", MS_BIND },
354d9f0492fSopenharmony_ci    { "rec", MS_REC },
355d9f0492fSopenharmony_ci    { "unbindable", MS_UNBINDABLE },
356d9f0492fSopenharmony_ci    { "private", MS_PRIVATE },
357d9f0492fSopenharmony_ci    { "slave", MS_SLAVE },
358d9f0492fSopenharmony_ci    { "shared", MS_SHARED },
359d9f0492fSopenharmony_ci    { "defaults", 0 },
360d9f0492fSopenharmony_ci};
361d9f0492fSopenharmony_ci
362d9f0492fSopenharmony_cistatic bool IsDefaultMountFlags(const char *str)
363d9f0492fSopenharmony_ci{
364d9f0492fSopenharmony_ci    bool isDefault = false;
365d9f0492fSopenharmony_ci
366d9f0492fSopenharmony_ci    if (str != NULL) {
367d9f0492fSopenharmony_ci        for (size_t i = 0; i < ARRAY_LENGTH(MOUNT_FLAGS); i++) {
368d9f0492fSopenharmony_ci            if (strcmp(str, MOUNT_FLAGS[i].name) == 0) {
369d9f0492fSopenharmony_ci                isDefault = true;
370d9f0492fSopenharmony_ci            }
371d9f0492fSopenharmony_ci        }
372d9f0492fSopenharmony_ci    }
373d9f0492fSopenharmony_ci    return isDefault;
374d9f0492fSopenharmony_ci}
375d9f0492fSopenharmony_ci
376d9f0492fSopenharmony_cistatic unsigned long ParseDefaultMountFlag(const char *str)
377d9f0492fSopenharmony_ci{
378d9f0492fSopenharmony_ci    unsigned long flags = 0;
379d9f0492fSopenharmony_ci
380d9f0492fSopenharmony_ci    if (str != NULL) {
381d9f0492fSopenharmony_ci        for (size_t i = 0; i < ARRAY_LENGTH(MOUNT_FLAGS); i++) {
382d9f0492fSopenharmony_ci            if (strcmp(str, MOUNT_FLAGS[i].name) == 0) {
383d9f0492fSopenharmony_ci                flags = MOUNT_FLAGS[i].flags;
384d9f0492fSopenharmony_ci                break;
385d9f0492fSopenharmony_ci            }
386d9f0492fSopenharmony_ci        }
387d9f0492fSopenharmony_ci    }
388d9f0492fSopenharmony_ci    return flags;
389d9f0492fSopenharmony_ci}
390d9f0492fSopenharmony_ci
391d9f0492fSopenharmony_cistatic bool IsFscryptOption(const char *option)
392d9f0492fSopenharmony_ci{
393d9f0492fSopenharmony_ci    if (!option) {
394d9f0492fSopenharmony_ci        return false;
395d9f0492fSopenharmony_ci    }
396d9f0492fSopenharmony_ci    char *fscryptPre = "fscrypt=";
397d9f0492fSopenharmony_ci    if (strncmp(option, fscryptPre, strlen(fscryptPre)) == 0) {
398d9f0492fSopenharmony_ci        return true;
399d9f0492fSopenharmony_ci    }
400d9f0492fSopenharmony_ci    return false;
401d9f0492fSopenharmony_ci}
402d9f0492fSopenharmony_ci
403d9f0492fSopenharmony_cistatic void StoreFscryptPolicy(const char *option)
404d9f0492fSopenharmony_ci{
405d9f0492fSopenharmony_ci    if (option == NULL) {
406d9f0492fSopenharmony_ci        return;
407d9f0492fSopenharmony_ci    }
408d9f0492fSopenharmony_ci
409d9f0492fSopenharmony_ci    char fscryptDisable[CMDLINE_VALUE_LEN_MAX] = {0};
410d9f0492fSopenharmony_ci    int ret = GetParameterFromCmdLine(CMDLINE_LABEL_FSCRYPT_DISABLE, fscryptDisable, sizeof(fscryptDisable));
411d9f0492fSopenharmony_ci    if (ret == 0 && strncmp(fscryptDisable,
412d9f0492fSopenharmony_ci                            CMDLINE_VALUE_FSCRYPT_DISABLE, CMDLINE_VALUE_LEN) == 0) {
413d9f0492fSopenharmony_ci        BEGET_LOGE("fscrypt policy is disabled by cmdline");
414d9f0492fSopenharmony_ci        return;
415d9f0492fSopenharmony_ci    }
416d9f0492fSopenharmony_ci
417d9f0492fSopenharmony_ci    if (g_fscryptPolicy != NULL) {
418d9f0492fSopenharmony_ci        BEGET_LOGW("StoreFscryptPolicy:inited policy is not empty");
419d9f0492fSopenharmony_ci        free(g_fscryptPolicy);
420d9f0492fSopenharmony_ci    }
421d9f0492fSopenharmony_ci    g_fscryptPolicy = strdup(option);
422d9f0492fSopenharmony_ci    if (g_fscryptPolicy == NULL) {
423d9f0492fSopenharmony_ci        BEGET_LOGE("StoreFscryptPolicy:no memory");
424d9f0492fSopenharmony_ci        return;
425d9f0492fSopenharmony_ci    }
426d9f0492fSopenharmony_ci    BEGET_LOGI("StoreFscryptPolicy:store fscrypt policy, %s", option);
427d9f0492fSopenharmony_ci}
428d9f0492fSopenharmony_ci
429d9f0492fSopenharmony_ciint LoadFscryptPolicy(char *buf, size_t size)
430d9f0492fSopenharmony_ci{
431d9f0492fSopenharmony_ci    BEGET_LOGI("LoadFscryptPolicy start");
432d9f0492fSopenharmony_ci    if (buf == NULL || g_fscryptPolicy == NULL) {
433d9f0492fSopenharmony_ci        BEGET_LOGE("LoadFscryptPolicy:buf or fscrypt policy is empty");
434d9f0492fSopenharmony_ci        return -ENOMEM;
435d9f0492fSopenharmony_ci    }
436d9f0492fSopenharmony_ci    if (size == 0) {
437d9f0492fSopenharmony_ci        BEGET_LOGE("LoadFscryptPloicy:size is invalid");
438d9f0492fSopenharmony_ci        return -EINVAL;
439d9f0492fSopenharmony_ci    }
440d9f0492fSopenharmony_ci    if (strcpy_s(buf, size, g_fscryptPolicy) != 0) {
441d9f0492fSopenharmony_ci        BEGET_LOGE("loadFscryptPolicy:strcmp failed, error = %d", errno);
442d9f0492fSopenharmony_ci        return -EFAULT;
443d9f0492fSopenharmony_ci    }
444d9f0492fSopenharmony_ci    free(g_fscryptPolicy);
445d9f0492fSopenharmony_ci    g_fscryptPolicy = NULL;
446d9f0492fSopenharmony_ci    BEGET_LOGI("LoadFscryptPolicy success");
447d9f0492fSopenharmony_ci
448d9f0492fSopenharmony_ci    return 0;
449d9f0492fSopenharmony_ci}
450d9f0492fSopenharmony_ci
451d9f0492fSopenharmony_ciunsigned long GetMountFlags(char *mountFlag, char *fsSpecificData, size_t fsSpecificDataSize,
452d9f0492fSopenharmony_ci    const char *mountPoint)
453d9f0492fSopenharmony_ci{
454d9f0492fSopenharmony_ci    unsigned long flags = 0;
455d9f0492fSopenharmony_ci    BEGET_CHECK_RETURN_VALUE(mountFlag != NULL && fsSpecificData != NULL, 0);
456d9f0492fSopenharmony_ci    int flagCount = 0;
457d9f0492fSopenharmony_ci    // Why max count of mount flags is 15?
458d9f0492fSopenharmony_ci    // There are lots for mount flags defined in sys/mount.h
459d9f0492fSopenharmony_ci    // But we only support to parse 15 in @ParseDefaultMountFlags() function
460d9f0492fSopenharmony_ci    // So set default mount flag number to 15.
461d9f0492fSopenharmony_ci    // If the item configured in fstab contains flag over than 15,
462d9f0492fSopenharmony_ci    // @SplitStringExt can handle it and parse them all. but the parse function will drop it.
463d9f0492fSopenharmony_ci    const int maxCount = 15;
464d9f0492fSopenharmony_ci    char **flagsVector = SplitStringExt(mountFlag, ",", &flagCount, maxCount);
465d9f0492fSopenharmony_ci
466d9f0492fSopenharmony_ci    if (flagsVector == NULL || flagCount == 0) {
467d9f0492fSopenharmony_ci        // No flags or something wrong in SplitStringExt,just return.
468d9f0492fSopenharmony_ci        return 0;
469d9f0492fSopenharmony_ci    }
470d9f0492fSopenharmony_ci
471d9f0492fSopenharmony_ci    for (int i = 0; i < flagCount; i++) {
472d9f0492fSopenharmony_ci        char *p = flagsVector[i];
473d9f0492fSopenharmony_ci        if (IsDefaultMountFlags(p)) {
474d9f0492fSopenharmony_ci            flags |= ParseDefaultMountFlag(p);
475d9f0492fSopenharmony_ci        } else {
476d9f0492fSopenharmony_ci            if (IsFscryptOption(p) &&
477d9f0492fSopenharmony_ci                !strncmp(mountPoint, "/data", strlen("/data"))) {
478d9f0492fSopenharmony_ci                StoreFscryptPolicy(p + strlen("fscrypt="));
479d9f0492fSopenharmony_ci                continue;
480d9f0492fSopenharmony_ci            }
481d9f0492fSopenharmony_ci            if (strncat_s(fsSpecificData, fsSpecificDataSize - 1, p, strlen(p)) != EOK) {
482d9f0492fSopenharmony_ci                BEGET_LOGW("Failed to append mount flag \" %s \", ignore it.", p);
483d9f0492fSopenharmony_ci                continue;
484d9f0492fSopenharmony_ci            }
485d9f0492fSopenharmony_ci            if (i == flagCount - 1) { // last flags, do not need to append ','
486d9f0492fSopenharmony_ci                break;
487d9f0492fSopenharmony_ci            }
488d9f0492fSopenharmony_ci            // Combined each mount flag with ','
489d9f0492fSopenharmony_ci            if (strncat_s(fsSpecificData, fsSpecificDataSize - 1, ",", 1) != EOK) {
490d9f0492fSopenharmony_ci                BEGET_LOGW("Failed to append comma");
491d9f0492fSopenharmony_ci                break; // If cannot add ',' to the end of flags, there is not reason to continue.
492d9f0492fSopenharmony_ci            }
493d9f0492fSopenharmony_ci        }
494d9f0492fSopenharmony_ci    }
495d9f0492fSopenharmony_ci
496d9f0492fSopenharmony_ci    FreeStringVector(flagsVector, flagCount);
497d9f0492fSopenharmony_ci    return flags;
498d9f0492fSopenharmony_ci}
499d9f0492fSopenharmony_ci
500d9f0492fSopenharmony_ciint GetBlockDevicePath(const char *partName, char *path, size_t size)
501d9f0492fSopenharmony_ci{
502d9f0492fSopenharmony_ci    BEGET_CHECK_RETURN_VALUE(partName != NULL && path != NULL, -1);
503d9f0492fSopenharmony_ci    Fstab *fstab = LoadFstabFromCommandLine();
504d9f0492fSopenharmony_ci    if (fstab == NULL) {
505d9f0492fSopenharmony_ci        BEGET_LOGI("fstab not found from cmdline, try to get it from file");
506d9f0492fSopenharmony_ci        char *fstabFile = GetFstabFile(path, size);
507d9f0492fSopenharmony_ci        BEGET_CHECK_RETURN_VALUE(fstabFile != NULL, -1);
508d9f0492fSopenharmony_ci        fstab = ReadFstabFromFile(fstabFile, false);
509d9f0492fSopenharmony_ci    }
510d9f0492fSopenharmony_ci    BEGET_CHECK_RETURN_VALUE(fstab != NULL, -1);
511d9f0492fSopenharmony_ci    int ret = GetBlockDeviceByMountPoint(partName, fstab, path, size);
512d9f0492fSopenharmony_ci    BEGET_INFO_CHECK(ret == 0, ret = GetBlockDeviceByName(partName, fstab, path, size),
513d9f0492fSopenharmony_ci        "Mount point not found, try to get path by device name.");
514d9f0492fSopenharmony_ci    ReleaseFstab(fstab);
515d9f0492fSopenharmony_ci    return ret;
516d9f0492fSopenharmony_ci}
517d9f0492fSopenharmony_ci
518d9f0492fSopenharmony_ci#define OHOS_REQUIRED_MOUNT_PREFIX "ohos.required_mount."
519d9f0492fSopenharmony_ci/*
520d9f0492fSopenharmony_ci * Fstab includes block device node, mount point, file system type, MNT_ Flags and options.
521d9f0492fSopenharmony_ci * We separate them by spaces in fstab.required file, but the separator is '@' in CmdLine.
522d9f0492fSopenharmony_ci * The prefix "ohos.required_mount." is the flag of required fstab information in CmdLine.
523d9f0492fSopenharmony_ci * Format as shown below:
524d9f0492fSopenharmony_ci * <block device>@<mount point>@<fstype>@<mount options>@<fstab options>
525d9f0492fSopenharmony_ci * e.g.
526d9f0492fSopenharmony_ci * ohos.required_mount.system=/dev/block/xxx/by-name/system@/usr@ext4@ro,barrier=1@wait,required
527d9f0492fSopenharmony_ci */
528d9f0492fSopenharmony_cistatic int ParseRequiredMountInfo(const char *item, Fstab *fstab)
529d9f0492fSopenharmony_ci{
530d9f0492fSopenharmony_ci    char mountOptions[MAX_BUFFER_LEN] = {};
531d9f0492fSopenharmony_ci    char partName[NAME_SIZE] = {};
532d9f0492fSopenharmony_ci    // Sanity checks
533d9f0492fSopenharmony_ci    BEGET_CHECK(!(item == NULL || *item == '\0' || fstab == NULL), return -1);
534d9f0492fSopenharmony_ci
535d9f0492fSopenharmony_ci    char *p = NULL;
536d9f0492fSopenharmony_ci    if ((p = strstr(item, "=")) != NULL) {
537d9f0492fSopenharmony_ci        const char *q = item + strlen(OHOS_REQUIRED_MOUNT_PREFIX); // Get partition name
538d9f0492fSopenharmony_ci        BEGET_CHECK(!(q == NULL || *q == '\0' || (p - q) <= 0), return -1);
539d9f0492fSopenharmony_ci        BEGET_ERROR_CHECK(strncpy_s(partName, NAME_SIZE -1, q, p - q) == EOK,
540d9f0492fSopenharmony_ci            return -1, "Failed to copy required partition name");
541d9f0492fSopenharmony_ci        p++; // skip '='
542d9f0492fSopenharmony_ci        BEGET_ERROR_CHECK(strncpy_s(mountOptions, MAX_BUFFER_LEN -1, p, strlen(p)) == EOK,
543d9f0492fSopenharmony_ci            return -1, "Failed to copy required mount info: %s", item);
544d9f0492fSopenharmony_ci    }
545d9f0492fSopenharmony_ci    BEGET_LOGV("Config mount option of partition %s is [%s]", partName, mountOptions);
546d9f0492fSopenharmony_ci    if (ParseFstabPerLine(mountOptions, fstab, false, "@") < 0) {
547d9f0492fSopenharmony_ci        BEGET_LOGE("Failed to parse mount options of partition \' %s \', options: %s", partName, mountOptions);
548d9f0492fSopenharmony_ci        return -1;
549d9f0492fSopenharmony_ci    }
550d9f0492fSopenharmony_ci    return 0;
551d9f0492fSopenharmony_ci}
552d9f0492fSopenharmony_ci
553d9f0492fSopenharmony_ciFstab* LoadFstabFromCommandLine(void)
554d9f0492fSopenharmony_ci{
555d9f0492fSopenharmony_ci    Fstab *fstab = NULL;
556d9f0492fSopenharmony_ci    char *cmdline = ReadFileData(BOOT_CMD_LINE);
557d9f0492fSopenharmony_ci    bool isDone = false;
558d9f0492fSopenharmony_ci
559d9f0492fSopenharmony_ci    BEGET_ERROR_CHECK(cmdline != NULL, return NULL, "Read from \'%s\' failed, err = %d", BOOT_CMD_LINE, errno);
560d9f0492fSopenharmony_ci    TrimTail(cmdline, '\n');
561d9f0492fSopenharmony_ci    fstab = (Fstab *)calloc(1, sizeof(Fstab));
562d9f0492fSopenharmony_ci    BEGET_ERROR_CHECK(fstab != NULL, free(cmdline); return NULL,
563d9f0492fSopenharmony_ci        "Allocate memory for FS table failed, err = %d", errno);
564d9f0492fSopenharmony_ci    char *start = cmdline;
565d9f0492fSopenharmony_ci    char *end = start + strlen(cmdline);
566d9f0492fSopenharmony_ci    while (start < end) {
567d9f0492fSopenharmony_ci        char *token = strstr(start, " ");
568d9f0492fSopenharmony_ci        if (token == NULL) {
569d9f0492fSopenharmony_ci            break;
570d9f0492fSopenharmony_ci        }
571d9f0492fSopenharmony_ci
572d9f0492fSopenharmony_ci        // Startswith " "
573d9f0492fSopenharmony_ci        if (token == start) {
574d9f0492fSopenharmony_ci            start++;
575d9f0492fSopenharmony_ci            continue;
576d9f0492fSopenharmony_ci        }
577d9f0492fSopenharmony_ci        *token = '\0';
578d9f0492fSopenharmony_ci        if (strncmp(start, OHOS_REQUIRED_MOUNT_PREFIX,
579d9f0492fSopenharmony_ci            strlen(OHOS_REQUIRED_MOUNT_PREFIX)) != 0) {
580d9f0492fSopenharmony_ci            start = token + 1;
581d9f0492fSopenharmony_ci            continue;
582d9f0492fSopenharmony_ci        }
583d9f0492fSopenharmony_ci        isDone = true;
584d9f0492fSopenharmony_ci        if (ParseRequiredMountInfo(start, fstab) < 0) {
585d9f0492fSopenharmony_ci            BEGET_LOGE("Failed to parse \' %s \'", start);
586d9f0492fSopenharmony_ci            isDone = false;
587d9f0492fSopenharmony_ci            break;
588d9f0492fSopenharmony_ci        }
589d9f0492fSopenharmony_ci        start = token + 1;
590d9f0492fSopenharmony_ci    }
591d9f0492fSopenharmony_ci
592d9f0492fSopenharmony_ci    // handle last one
593d9f0492fSopenharmony_ci    if (start < end) {
594d9f0492fSopenharmony_ci        if (strncmp(start, OHOS_REQUIRED_MOUNT_PREFIX,
595d9f0492fSopenharmony_ci            strlen(OHOS_REQUIRED_MOUNT_PREFIX)) == 0 &&
596d9f0492fSopenharmony_ci            ParseRequiredMountInfo(start, fstab) < 0) {
597d9f0492fSopenharmony_ci            BEGET_LOGE("Failed to parse \' %s \'", start);
598d9f0492fSopenharmony_ci            isDone = false;
599d9f0492fSopenharmony_ci        }
600d9f0492fSopenharmony_ci    }
601d9f0492fSopenharmony_ci
602d9f0492fSopenharmony_ci    if (!isDone) {
603d9f0492fSopenharmony_ci        ReleaseFstab(fstab);
604d9f0492fSopenharmony_ci        fstab = NULL;
605d9f0492fSopenharmony_ci    }
606d9f0492fSopenharmony_ci    free(cmdline);
607d9f0492fSopenharmony_ci    return fstab;
608d9f0492fSopenharmony_ci}
609d9f0492fSopenharmony_ci#ifdef __cplusplus
610d9f0492fSopenharmony_ci#if __cplusplus
611d9f0492fSopenharmony_ci}
612d9f0492fSopenharmony_ci#endif
613d9f0492fSopenharmony_ci#endif
614