fstab.c 11.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * 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 27
#include <string.h>
#include <stdbool.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "fs_manager/fs_manager.h"
X
xionglei6 已提交
28
#include "fs_manager/fs_manager_log.h"
X
add ut  
xionglei6 已提交
29
#include "init_log.h"
30 31 32
#include "init_utils.h"
#include "securec.h"

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

39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
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
add ut  
xionglei6 已提交
57
    INIT_CHECK_RETURN_VALUE(flagBuffer != NULL && *flagBuffer != '\0', 0); // No valid flags.
58 59 60 61
    int flagCount = 0;
    unsigned int flags = 0;
    const int maxCount = 3;
    char **vector = SplitStringExt(flagBuffer, ",", &flagCount, maxCount);
X
add ut  
xionglei6 已提交
62
    INIT_CHECK_RETURN_VALUE(vector != NULL && flagCount != 0, 0);
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
    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;
}

static void AddToFstab(Fstab *fstab, FstabItem *item)
{
    if (fstab == NULL || item == NULL) {
        return;
    }
    if (fstab->head != NULL) {
        item->next = fstab->head->next;
        fstab->head->next = item;
    } else {
        fstab->head = item;
    }
}

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 109 110
        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;
        }
        free(item);
        item = NULL;
S
sun_fan 已提交
111
    }
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
}

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

static int ParseFstabPerLine(char *str, Fstab *fstab, bool procMounts)
{
X
add ut  
xionglei6 已提交
130
    INIT_CHECK_RETURN_VALUE(str != NULL && fstab != NULL, -1);
131 132 133 134 135 136 137
    const char *separator = " \t";
    char *rest = NULL;
    FstabItem *item = NULL;
    char *p = NULL;

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

    do {
        if ((p = strtok_r(str, separator, &rest)) == NULL) {
X
xionglei6 已提交
144
            FSMGR_LOGE("Failed to parse block device.");
145 146 147 148 149
            break;
        }
        item->deviceName = strdup(p);

        if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
X
xionglei6 已提交
150
            FSMGR_LOGE("Failed to parse mount point.");
151 152 153 154 155
            break;
        }
        item->mountPoint = strdup(p);

        if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
X
xionglei6 已提交
156
            FSMGR_LOGE("Failed to parse fs type.");
157 158 159 160 161
            break;
        }
        item->fsType = strdup(p);

        if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
X
xionglei6 已提交
162
            FSMGR_LOGE("Failed to parse mount options.");
163 164 165 166 167
            break;
        }
        item->mountOptions = strdup(p);

        if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
X
xionglei6 已提交
168
            FSMGR_LOGE("Failed to parse fs manager flags.");
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
            break;
        }
        // @fsManagerFlags only for fstab
        // Ignore it if we read from /proc/mounts
        if (!procMounts) {
            item->fsManagerFlags = ConvertFlags(p);
        } else {
            item->fsManagerFlags = 0;
        }
        AddToFstab(fstab, item);
        return 0;
    } while (0);

    free(item);
    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 已提交
194 195
    char *realPath = GetRealPath(file);
    if (realPath == NULL) {
X
xionglei6 已提交
196
        FSMGR_LOGE("Invalid file");
197 198
        return NULL;
    }
X
xionglei6 已提交
199 200
    FILE *fp = fopen(realPath, "r");
    free(realPath);
201
    if (fp == NULL) {
X
xionglei6 已提交
202
        FSMGR_LOGE("Open %s failed, err = %d", file, errno);
203 204 205 206
        return NULL;
    }

    if ((fstab = (Fstab *)calloc(1, sizeof(Fstab))) == NULL) {
X
xionglei6 已提交
207
        FSMGR_LOGE("Allocate memory for FS table failed, err = %d", errno);
S
sun_fan 已提交
208 209
        fclose(fp);
        fp = NULL;
210 211 212 213 214 215 216 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;
        }

        if (ParseFstabPerLine(p, fstab, procMounts) < 0) {
            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 已提交
237
            FSMGR_LOGW("Cannot parse file \" %s \" at line %zu. skip it", file, ln);
238 239 240 241 242 243
            continue;
        }
    }
    if (line != NULL) {
        free(line);
    }
S
sun_fan 已提交
244
    (void)fclose(fp);
S
sun_fan 已提交
245
    fp = NULL;
246 247 248 249 250 251 252 253
    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 已提交
254
            if ((item->mountPoint != NULL) && (strcmp(item->mountPoint, mp) == 0)) {
255 256 257 258 259 260 261 262 263 264 265
                break;
            }
        }
    }
    return item;
}

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

X
add ut  
xionglei6 已提交
266
    if (path == NULL || *path == '\0') {
267 268 269 270 271
        return NULL;
    }

    char tmp[PATH_MAX] = {0};
    char *dir = NULL;
X
xionglei6 已提交
272
    if (strncpy_s(tmp, PATH_MAX - 1,  path, strlen(path)) != EOK) {
X
xionglei6 已提交
273
        FSMGR_LOGE("Failed to copy path.");
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
        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;
}

292 293 294 295 296 297 298 299 300
char *GetFstabFile(void)
{
    char file[PATH_MAX] = {0};
    if (InUpdaterMode() == 1) {
        if (strncpy_s(file, PATH_MAX, "/etc/fstab.updater", strlen("/etc/fstab.updater")) != 0) {
            FSMGR_LOGE("Failed strncpy_s err=%d", errno);
            return NULL;
        }
    } else {
X
xionglei6 已提交
301
        char hardware[MAX_BUFFER_LEN] = {0};
302 303 304 305 306
        char *buffer = ReadFileData("/proc/cmdline");
        if (buffer == NULL) {
            FSMGR_LOGE("Failed read \"/proc/cmdline\"");
            return NULL;
        }
X
xionglei6 已提交
307
        int ret = GetProcCmdlineValue("hardware", buffer, hardware, MAX_BUFFER_LEN);
308 309 310 311 312 313 314 315 316 317 318
        free(buffer);
        if (ret != 0) {
            FSMGR_LOGE("Failed get hardware from cmdline");
            return NULL;
        }
        if (snprintf_s(file, PATH_MAX, PATH_MAX - 1, "/vendor/etc/fstab.%s", hardware) == -1) {
            FSMGR_LOGE("Fail snprintf_s err=%d", errno);
            return NULL;
        }
    }
    FSMGR_LOGI("file is %s", file);
X
xionglei6 已提交
319
    return strdup(file); // After the return value is used up, it must be free.
320 321
}

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

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

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

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

    FreeStringVector(flagsVector, flagCount);
    return flags;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
433
#endif