fstab.c 13.4 KB
Newer Older
1
/*
M
Mupceet 已提交
2
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <ctype.h>
#include <libgen.h>
S
sun_fan 已提交
18 19
#include <limits.h>
#include <stdio.h>
20 21 22 23
#include <string.h>
#include <stdbool.h>
#include <sys/mount.h>
#include <sys/types.h>
X
xionglei6 已提交
24
#include "beget_ext.h"
25 26 27 28
#include "fs_manager/fs_manager.h"
#include "init_utils.h"
#include "securec.h"

S
sun_fan 已提交
29 30 31 32 33 34
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif

35 36 37 38 39 40 41 42 43 44
struct FsManagerFlags {
    char *name;
    unsigned int flags;
};

struct MountFlags {
    char *name;
    unsigned long flags;
};

45 46 47 48 49 50
#define POLICY_BUFFER (100)

static const char *g_fscryptPre = "fscrypt=";
static const char *g_mountPoint = "/data";
static char g_fscryptPolicy[POLICY_BUFFER] = { 0 };

51
static unsigned int ConvertFlags(char *flagBuffer)
52 53 54 55 56 57 58
{
    static struct FsManagerFlags fsFlags[] = {
        {"check", FS_MANAGER_CHECK},
        {"wait", FS_MANAGER_WAIT},
        {"required", FS_MANAGER_REQUIRED},
    };

X
xionglei6 已提交
59
    BEGET_CHECK_RETURN_VALUE(flagBuffer != NULL && *flagBuffer != '\0', 0); // No valid flags.
60 61 62 63
    int flagCount = 0;
    unsigned int flags = 0;
    const int maxCount = 3;
    char **vector = SplitStringExt(flagBuffer, ",", &flagCount, maxCount);
X
xionglei6 已提交
64
    BEGET_CHECK_RETURN_VALUE(vector != NULL && flagCount != 0, 0);
65 66 67 68 69 70 71 72 73 74 75
    for (size_t i = 0; i < ARRAY_LENGTH(fsFlags); i++) {
        for (int j = 0; j < flagCount; j++) {
            if (strcmp(fsFlags[i].name, vector[j]) == 0) {
                flags |= fsFlags[i].flags;
            }
        }
    }
    FreeStringVector(vector, flagCount);
    return flags;
}

M
Mupceet 已提交
76
static int AddToFstab(Fstab *fstab, FstabItem *item)
77 78
{
    if (fstab == NULL || item == NULL) {
M
Mupceet 已提交
79
        return -1;
80 81 82 83 84 85 86
    }
    if (fstab->head != NULL) {
        item->next = fstab->head->next;
        fstab->head->next = item;
    } else {
        fstab->head = item;
    }
M
Mupceet 已提交
87
    return 0;
88 89 90 91
}

void ReleaseFstabItem(FstabItem *item)
{
S
sun_fan 已提交
92
    if (item != NULL) {
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
        if (item->deviceName != NULL) {
            free(item->deviceName);
            item->deviceName = NULL;
        }

        if (item->mountPoint != NULL) {
            free(item->mountPoint);
            item->mountPoint = NULL;
        }

        if (item->fsType != NULL) {
            free(item->fsType);
            item->fsType = NULL;
        }

        if (item->mountOptions != NULL) {
            free(item->mountOptions);
            item->mountOptions = NULL;
        }
X
xionglei6 已提交
112

113
        free(item);
S
sun_fan 已提交
114
    }
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
}

void ReleaseFstab(Fstab *fstab)
{
    if (fstab != NULL) {
        FstabItem *item = fstab->head;
        while (item != NULL) {
            FstabItem *tmp = item->next;
            ReleaseFstabItem(item);
            item = tmp;
        }
        free(fstab);
        fstab = NULL;
    }
}

M
Mupceet 已提交
131
int ParseFstabPerLine(char *str, Fstab *fstab, bool procMounts, const char *separator)
132
{
X
xionglei6 已提交
133
    BEGET_CHECK_RETURN_VALUE(str != NULL && fstab != NULL, -1);
134 135 136 137
    char *rest = NULL;
    FstabItem *item = NULL;
    char *p = NULL;

M
Mupceet 已提交
138 139 140 141 142
    if (separator == NULL || *separator == '\0') {
        BEGET_LOGE("Invalid separator for parsing fstab");
        return -1;
    }

143 144
    if ((item = (FstabItem *)calloc(1, sizeof(FstabItem))) == NULL) {
        errno = ENOMEM;
X
xionglei6 已提交
145
        BEGET_LOGE("Allocate memory for FS table item failed, err = %d", errno);
146 147 148 149 150
        return -1;
    }

    do {
        if ((p = strtok_r(str, separator, &rest)) == NULL) {
X
xionglei6 已提交
151
            BEGET_LOGE("Failed to parse block device.");
152 153 154 155 156
            break;
        }
        item->deviceName = strdup(p);

        if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
X
xionglei6 已提交
157
            BEGET_LOGE("Failed to parse mount point.");
158 159 160 161 162
            break;
        }
        item->mountPoint = strdup(p);

        if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
X
xionglei6 已提交
163
            BEGET_LOGE("Failed to parse fs type.");
164 165 166 167 168
            break;
        }
        item->fsType = strdup(p);

        if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
X
xionglei6 已提交
169
            BEGET_LOGE("Failed to parse mount options.");
170 171 172 173 174
            break;
        }
        item->mountOptions = strdup(p);

        if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
X
xionglei6 已提交
175
            BEGET_LOGE("Failed to parse fs manager flags.");
176 177 178 179 180 181 182 183 184
            break;
        }
        // @fsManagerFlags only for fstab
        // Ignore it if we read from /proc/mounts
        if (!procMounts) {
            item->fsManagerFlags = ConvertFlags(p);
        } else {
            item->fsManagerFlags = 0;
        }
M
Mupceet 已提交
185
        return AddToFstab(fstab, item);
186 187
    } while (0);

X
xionglei6 已提交
188
    ReleaseFstabItem(item);
189 190 191 192 193 194 195 196 197 198 199
    item = NULL;
    return -1;
}

Fstab *ReadFstabFromFile(const char *file, bool procMounts)
{
    char *line = NULL;
    size_t allocn = 0;
    ssize_t readn = 0;
    Fstab *fstab = NULL;

X
xionglei6 已提交
200
    FILE *fp = NULL;
X
xionglei6 已提交
201
    char *realPath = GetRealPath(file);
X
xionglei6 已提交
202 203 204 205 206
    if (realPath != NULL) {
        fp = fopen(realPath, "r");
        free(realPath);
    } else {
        fp = fopen(file, "r"); // no file system, can not get real path
207 208
    }
    if (fp == NULL) {
X
xionglei6 已提交
209
        BEGET_LOGE("Open %s failed, err = %d", file, errno);
210 211 212 213
        return NULL;
    }

    if ((fstab = (Fstab *)calloc(1, sizeof(Fstab))) == NULL) {
X
xionglei6 已提交
214
        BEGET_LOGE("Allocate memory for FS table failed, err = %d", errno);
S
sun_fan 已提交
215 216
        fclose(fp);
        fp = NULL;
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
        return NULL;
    }

    // Record line number of fstab file
    size_t ln = 0;
    while ((readn = getline(&line, &allocn, fp)) != -1) {
        char *p = NULL;
        ln++;
        if (line[readn - 1] == '\n') {
            line[readn - 1] = '\0';
        }
        p = line;
        while (isspace(*p)) {
            p++;
        }

        if (*p == '\0' || *p == '#') {
            continue;
        }

M
Mupceet 已提交
237
        if (ParseFstabPerLine(p, fstab, procMounts, " \t") < 0) {
238 239 240 241 242 243
            if (errno == ENOMEM) {
                // Ran out of memory, there is no reason to continue.
                break;
            }
            // If one line in fstab file parsed with a failure. just give a warning
            // and skip it.
X
xionglei6 已提交
244
            BEGET_LOGW("Cannot parse file \" %s \" at line %zu. skip it", file, ln);
245 246 247 248 249 250
            continue;
        }
    }
    if (line != NULL) {
        free(line);
    }
S
sun_fan 已提交
251
    (void)fclose(fp);
S
sun_fan 已提交
252
    fp = NULL;
253 254 255 256 257 258 259 260
    return fstab;
}

FstabItem *FindFstabItemForMountPoint(Fstab fstab, const char *mp)
{
    FstabItem *item = NULL;
    if (mp != NULL) {
        for (item = fstab.head; item != NULL; item = item->next) {
X
xionglei6 已提交
261
            if ((item->mountPoint != NULL) && (strcmp(item->mountPoint, mp) == 0)) {
262 263 264 265 266 267 268 269 270 271 272
                break;
            }
        }
    }
    return item;
}

FstabItem *FindFstabItemForPath(Fstab fstab, const char *path)
{
    FstabItem *item = NULL;

X
add ut  
xionglei6 已提交
273
    if (path == NULL || *path == '\0') {
274 275 276 277 278
        return NULL;
    }

    char tmp[PATH_MAX] = {0};
    char *dir = NULL;
X
xionglei6 已提交
279
    if (strncpy_s(tmp, PATH_MAX - 1,  path, strlen(path)) != EOK) {
X
xionglei6 已提交
280
        BEGET_LOGE("Failed to copy path.");
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
        return NULL;
    }

    dir = tmp;
    while (true) {
        item = FindFstabItemForMountPoint(fstab, dir);
        if (item != NULL) {
            break;
        }
        dir = dirname(dir);
        // Reverse walk through path and met "/", just quit.
        if (dir == NULL || strcmp(dir, "/") == 0) {
            break;
        }
    }
    return item;
}

X
xionglei6 已提交
299
static char *GetFstabFile(char *fileName, int size)
300 301
{
    if (InUpdaterMode() == 1) {
X
xionglei6 已提交
302
        if (strncpy_s(fileName, size, "/etc/fstab.updater", strlen("/etc/fstab.updater")) != 0) {
X
xionglei6 已提交
303
            BEGET_LOGE("Failed strncpy_s err=%d", errno);
304 305 306
            return NULL;
        }
    } else {
X
xionglei6 已提交
307
        char hardware[MAX_BUFFER_LEN] = {0};
308 309
        char *buffer = ReadFileData("/proc/cmdline");
        if (buffer == NULL) {
M
Mupceet 已提交
310
            BEGET_LOGE("Failed to read \"/proc/cmdline\"");
311 312
            return NULL;
        }
X
xionglei6 已提交
313
        int ret = GetProcCmdlineValue("hardware", buffer, hardware, MAX_BUFFER_LEN);
314 315
        free(buffer);
        if (ret != 0) {
X
xionglei6 已提交
316
            BEGET_LOGE("Failed get hardware from cmdline");
317 318
            return NULL;
        }
X
xionglei6 已提交
319
        if (snprintf_s(fileName, size, size - 1, "/vendor/etc/fstab.%s", hardware) == -1) {
M
Mupceet 已提交
320
            BEGET_LOGE("Failed to build fstab file, err=%d", errno);
321 322 323
            return NULL;
        }
    }
M
Mupceet 已提交
324
    BEGET_LOGI("fstab file is %s", fileName);
X
xionglei6 已提交
325
    return fileName;
326 327
}

X
xionglei6 已提交
328
int GetBlockDeviceByMountPoint(const char *mountPoint, const Fstab *fstab, char *deviceName, int nameLen)
329
{
X
xionglei6 已提交
330
    if (fstab == NULL || mountPoint == NULL || *mountPoint == '\0' || deviceName == NULL) {
331 332 333 334
        return -1;
    }
    FstabItem *item = FindFstabItemForMountPoint(*fstab, mountPoint);
    if (item == NULL) {
M
Mupceet 已提交
335
        BEGET_LOGE("Failed to get fstab item from point \" %s \"", mountPoint);
336 337 338
        return -1;
    }
    if (strncpy_s(deviceName, nameLen, item->deviceName, strlen(item->deviceName)) != 0) {
M
Mupceet 已提交
339
        BEGET_LOGE("Failed to copy block device name, err=%d", errno);
340 341 342 343 344
        return -1;
    }
    return 0;
}

345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
static const struct MountFlags mountFlags[] = {
    { "noatime", MS_NOATIME },
    { "noexec", MS_NOEXEC },
    { "nosuid", MS_NOSUID },
    { "nodev", MS_NODEV },
    { "nodiratime", MS_NODIRATIME },
    { "ro", MS_RDONLY },
    { "rw", 0 },
    { "sync", MS_SYNCHRONOUS },
    { "remount", MS_REMOUNT },
    { "bind", MS_BIND },
    { "rec", MS_REC },
    { "unbindable", MS_UNBINDABLE },
    { "private", MS_PRIVATE },
    { "slave", MS_SLAVE },
    { "shared", MS_SHARED },
    { "defaults", 0 },
};

S
sun_fan 已提交
364 365
static bool IsDefaultMountFlags(const char *str)
{
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
    bool isDefault = false;

    if (str != NULL) {
        for (size_t i = 0; i < ARRAY_LENGTH(mountFlags); i++) {
            if (strcmp(str, mountFlags[i].name) == 0) {
                isDefault = true;
            }
        }
    }
    return isDefault;
}

static unsigned long ParseDefaultMountFlag(const char *str)
{
    unsigned long flags = 0;

    if (str != NULL) {
S
sun_fan 已提交
383
        for (size_t i = 0; i < ARRAY_LENGTH(mountFlags); i++) {
384 385 386 387 388 389 390 391 392
            if (strcmp(str, mountFlags[i].name) == 0) {
                flags = mountFlags[i].flags;
                break;
            }
        }
    }
    return flags;
}

393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
static bool IsFscryptOption(const char *option)
{
    if (!option) {
        return false;
    }
    if (strncmp(option, g_fscryptPre, strlen(g_fscryptPre)) == 0) {
        return true;
    }
    return false;
}

static void StoreFscryptPolicy(const char *option)
{
    if (!option) {
        return;
    }
    if (strcpy_s(g_fscryptPolicy, POLICY_BUFFER - 1, option) != EOK) {
        g_fscryptPolicy[0] = '\0';
        BEGET_LOGE("StoreFscryptPolicy: copy policy failed");
        return;
    }
    BEGET_LOGI("StoreFscryptPolicy:load fscrypt policy, %s", option);
}

const char *LoadFscryptPolicy(void)
{
    if (strnlen(g_fscryptPolicy, POLICY_BUFFER - 1) == 0) {
        return NULL;
    }
    return g_fscryptPolicy;
}

unsigned long GetMountFlags(char *mountFlag, char *fsSpecificData, size_t fsSpecificDataSize,
    const char *mountPoint)
427 428
{
    unsigned long flags = 0;
X
xionglei6 已提交
429
    BEGET_CHECK_RETURN_VALUE(mountFlag != NULL && fsSpecificData != NULL, 0);
430 431 432 433 434 435 436 437
    int flagCount = 0;
    // Why max count of mount flags is 15?
    // There are lots for mount flags defined in sys/mount.h
    // But we only support to parse 15 in @ParseDefaultMountFlags() function
    // So set default mount flag number to 15.
    // If the item configured in fstab contains flag over than 15,
    // @SplitStringExt can handle it and parse them all. but the parse function will drop it.
    const int maxCount = 15;
S
sun_fan 已提交
438
    char **flagsVector = SplitStringExt(mountFlag, ",", &flagCount, maxCount);
439 440 441 442 443 444 445 446 447 448 449

    if (flagsVector == NULL || flagCount == 0) {
        // No flags or something wrong in SplitStringExt,just return.
        return 0;
    }

    for (int i = 0; i < flagCount; i++) {
        char *p = flagsVector[i];
        if (IsDefaultMountFlags(p)) {
            flags |= ParseDefaultMountFlag(p);
        } else {
450 451 452 453 454
            if (IsFscryptOption(p) &&
                !strncmp(mountPoint, g_mountPoint, strlen(g_mountPoint))) {
                StoreFscryptPolicy(p + strlen(g_fscryptPre));
                continue;
            }
455
            if (strncat_s(fsSpecificData, fsSpecificDataSize - 1, p, strlen(p)) != EOK) {
X
xionglei6 已提交
456
                BEGET_LOGW("Failed to append mount flag \" %s \", ignore it.", p);
457 458 459 460 461 462 463
                continue;
            }
            if (i == flagCount - 1) { // last flags, do not need to append ','
                break;
            }
            // Combined each mount flag with ','
            if (strncat_s(fsSpecificData, fsSpecificDataSize - 1, ",", 1) != EOK) {
M
Mupceet 已提交
464
                BEGET_LOGW("Failed to append comma");
465 466 467 468 469 470 471 472
                break; // If cannot add ',' to the end of flags, there is not reason to continue.
            }
        }
    }

    FreeStringVector(flagsVector, flagCount);
    return flags;
}
X
xionglei6 已提交
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488

int GetBlockDevicePath(const char *partName, char *path, int size)
{
    char *fstabFile = GetFstabFile(path, size);
    if (fstabFile == NULL) {
        return -1;
    }
    Fstab *fstab = ReadFstabFromFile(fstabFile, false);
    if (fstab == NULL) {
        return -1;
    }
    int ret = GetBlockDeviceByMountPoint(partName, fstab, path, size);
    ReleaseFstab(fstab);
    return ret;
}

489 490 491 492
#ifdef __cplusplus
#if __cplusplus
}
#endif
493
#endif