fstab.c 12.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 18
 * 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 <fcntl.h>
#include <libgen.h>
S
sun_fan 已提交
19 20
#include <limits.h>
#include <stdio.h>
21 22 23 24 25 26
#include <string.h>
#include <stdbool.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
X
xionglei6 已提交
27
#include "beget_ext.h"
28 29 30 31
#include "fs_manager/fs_manager.h"
#include "init_utils.h"
#include "securec.h"

S
sun_fan 已提交
32 33 34 35 36 37
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif

38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
struct FsManagerFlags {
    char *name;
    unsigned int flags;
};

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

unsigned int ConvertFlags(char *flagBuffer)
{
    static struct FsManagerFlags fsFlags[] = {
        {"check", FS_MANAGER_CHECK},
        {"wait", FS_MANAGER_WAIT},
        {"required", FS_MANAGER_REQUIRED},
    };

X
xionglei6 已提交
56
    BEGET_CHECK_RETURN_VALUE(flagBuffer != NULL && *flagBuffer != '\0', 0); // No valid flags.
57 58 59 60
    int flagCount = 0;
    unsigned int flags = 0;
    const int maxCount = 3;
    char **vector = SplitStringExt(flagBuffer, ",", &flagCount, maxCount);
X
xionglei6 已提交
61
    BEGET_CHECK_RETURN_VALUE(vector != NULL && flagCount != 0, 0);
62 63 64 65 66 67 68 69 70 71 72
    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 已提交
73
static int AddToFstab(Fstab *fstab, FstabItem *item)
74 75
{
    if (fstab == NULL || item == NULL) {
M
Mupceet 已提交
76
        return -1;
77 78 79 80 81 82 83
    }
    if (fstab->head != NULL) {
        item->next = fstab->head->next;
        fstab->head->next = item;
    } else {
        fstab->head = item;
    }
M
Mupceet 已提交
84
    return 0;
85 86 87 88
}

void ReleaseFstabItem(FstabItem *item)
{
S
sun_fan 已提交
89
    if (item != NULL) {
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
        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 已提交
109

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

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 已提交
128
int ParseFstabPerLine(char *str, Fstab *fstab, bool procMounts, const char *separator)
129
{
X
xionglei6 已提交
130
    BEGET_CHECK_RETURN_VALUE(str != NULL && fstab != NULL, -1);
131 132 133 134
    char *rest = NULL;
    FstabItem *item = NULL;
    char *p = NULL;

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

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

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

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

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

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

        if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
X
xionglei6 已提交
172
            BEGET_LOGE("Failed to parse fs manager flags.");
173 174 175 176 177 178 179 180 181
            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 已提交
182
        return AddToFstab(fstab, item);
183 184
    } while (0);

X
xionglei6 已提交
185
    ReleaseFstabItem(item);
186 187 188 189 190 191 192 193 194 195 196
    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 已提交
197
    FILE *fp = NULL;
X
xionglei6 已提交
198
    char *realPath = GetRealPath(file);
X
xionglei6 已提交
199 200 201 202 203
    if (realPath != NULL) {
        fp = fopen(realPath, "r");
        free(realPath);
    } else {
        fp = fopen(file, "r"); // no file system, can not get real path
204 205
    }
    if (fp == NULL) {
X
xionglei6 已提交
206
        BEGET_LOGE("Open %s failed, err = %d", file, errno);
207 208 209 210
        return NULL;
    }

    if ((fstab = (Fstab *)calloc(1, sizeof(Fstab))) == NULL) {
X
xionglei6 已提交
211
        BEGET_LOGE("Allocate memory for FS table failed, err = %d", errno);
S
sun_fan 已提交
212 213
        fclose(fp);
        fp = NULL;
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
        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 已提交
234
        if (ParseFstabPerLine(p, fstab, procMounts, " \t") < 0) {
235 236 237 238 239 240
            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 已提交
241
            BEGET_LOGW("Cannot parse file \" %s \" at line %zu. skip it", file, ln);
242 243 244 245 246 247
            continue;
        }
    }
    if (line != NULL) {
        free(line);
    }
S
sun_fan 已提交
248
    (void)fclose(fp);
S
sun_fan 已提交
249
    fp = NULL;
250 251 252 253 254 255 256 257
    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 已提交
258
            if ((item->mountPoint != NULL) && (strcmp(item->mountPoint, mp) == 0)) {
259 260 261 262 263 264 265 266 267 268 269
                break;
            }
        }
    }
    return item;
}

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

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

    char tmp[PATH_MAX] = {0};
    char *dir = NULL;
X
xionglei6 已提交
276
    if (strncpy_s(tmp, PATH_MAX - 1,  path, strlen(path)) != EOK) {
X
xionglei6 已提交
277
        BEGET_LOGE("Failed to copy path.");
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
        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 已提交
296
static char *GetFstabFile(char *fileName, int size)
297 298
{
    if (InUpdaterMode() == 1) {
X
xionglei6 已提交
299
        if (strncpy_s(fileName, size, "/etc/fstab.updater", strlen("/etc/fstab.updater")) != 0) {
X
xionglei6 已提交
300
            BEGET_LOGE("Failed strncpy_s err=%d", errno);
301 302 303
            return NULL;
        }
    } else {
X
xionglei6 已提交
304
        char hardware[MAX_BUFFER_LEN] = {0};
305 306
        char *buffer = ReadFileData("/proc/cmdline");
        if (buffer == NULL) {
M
Mupceet 已提交
307
            BEGET_LOGE("Failed to read \"/proc/cmdline\"");
308 309
            return NULL;
        }
X
xionglei6 已提交
310
        int ret = GetProcCmdlineValue("hardware", buffer, hardware, MAX_BUFFER_LEN);
311 312
        free(buffer);
        if (ret != 0) {
X
xionglei6 已提交
313
            BEGET_LOGE("Failed get hardware from cmdline");
314 315
            return NULL;
        }
X
xionglei6 已提交
316
        if (snprintf_s(fileName, size, size - 1, "/vendor/etc/fstab.%s", hardware) == -1) {
M
Mupceet 已提交
317
            BEGET_LOGE("Failed to build fstab file, err=%d", errno);
318 319 320
            return NULL;
        }
    }
M
Mupceet 已提交
321
    BEGET_LOGI("fstab file is %s", fileName);
X
xionglei6 已提交
322
    return fileName;
323 324
}

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

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
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 已提交
361 362
static bool IsDefaultMountFlags(const char *str)
{
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
    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 已提交
380
        for (size_t i = 0; i < ARRAY_LENGTH(mountFlags); i++) {
381 382 383 384 385 386 387 388 389
            if (strcmp(str, mountFlags[i].name) == 0) {
                flags = mountFlags[i].flags;
                break;
            }
        }
    }
    return flags;
}

S
sun_fan 已提交
390
unsigned long GetMountFlags(char *mountFlag, char *fsSpecificData, size_t fsSpecificDataSize)
391 392
{
    unsigned long flags = 0;
X
xionglei6 已提交
393
    BEGET_CHECK_RETURN_VALUE(mountFlag != NULL && fsSpecificData != NULL, 0);
394 395 396 397 398 399 400 401
    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 已提交
402
    char **flagsVector = SplitStringExt(mountFlag, ",", &flagCount, maxCount);
403 404 405 406 407 408 409 410 411 412 413 414

    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 {
            if (strncat_s(fsSpecificData, fsSpecificDataSize - 1, p, strlen(p)) != EOK) {
X
xionglei6 已提交
415
                BEGET_LOGW("Failed to append mount flag \" %s \", ignore it.", p);
416 417 418 419 420 421 422
                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 已提交
423
                BEGET_LOGW("Failed to append comma");
424 425 426 427 428 429 430 431
                break; // If cannot add ',' to the end of flags, there is not reason to continue.
            }
        }
    }

    FreeStringVector(flagsVector, flagCount);
    return flags;
}
X
xionglei6 已提交
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447

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;
}

448 449 450 451
#ifdef __cplusplus
#if __cplusplus
}
#endif
452
#endif