/* * Copyright (c) 2023 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 "init_eng.h" #include #include #include #include "plugin_adapter.h" #include "init_cmds.h" #include "init_utils.h" #include "init_module_engine.h" #include "securec.h" #define ENG_SYSTEM_DEVICE_PATH "/dev/block/by-name/eng_system" #define ENG_CHIPSET_DEVICE_PATH "/dev/block/by-name/eng_chipset" ENG_STATIC bool IsFileExistWithType(const char *file, FileType type) { bool isExist = false; struct stat st = {}; if (lstat(file, &st) == 0) { switch (type) { case TYPE_DIR: if (S_ISDIR(st.st_mode)) { isExist = true; } break; case TYPE_REG: if (S_ISREG(st.st_mode)) { isExist = true; } break; case TYPE_LINK: if (S_ISLNK(st.st_mode)) { isExist = true; } break; case TYPE_ANY: // fallthrough default: isExist = true; break; } } return isExist; } static bool IsRegularFile(const char *file) { return file == NULL ? false : IsFileExistWithType(file, TYPE_REG); } static bool IsExistFile(const char *file) { return file == NULL ? false : IsFileExistWithType(file, TYPE_ANY); } ENG_STATIC void BuildMountCmd(char *buffer, size_t len, const char *mp, const char *dev, const char *fstype) { int ret = snprintf_s(buffer, len, len - 1, "%s %s %s ro barrier=1", fstype, dev, mp); if (ret == -1) { *buffer = '\0'; } } ENG_STATIC void MountEngPartitions(void) { char mountCmd[MOUNT_CMD_MAX_LEN] = {}; // Mount eng_system BuildMountCmd(mountCmd, MOUNT_CMD_MAX_LEN, "/eng_system", "/dev/block/by-name/eng_system", "ext4"); WaitForFile(ENG_SYSTEM_DEVICE_PATH, WAIT_MAX_SECOND); DoCmdByName("mount ", mountCmd); // Mount eng_chipset BuildMountCmd(mountCmd, MOUNT_CMD_MAX_LEN, "/eng_chipset", "/dev/block/by-name/eng_chipset", "ext4"); WaitForFile(ENG_CHIPSET_DEVICE_PATH, WAIT_MAX_SECOND); DoCmdByName("mount ", mountCmd); } ENG_STATIC void BindMountFile(const char *source, const char *target) { char targetFullPath[PATH_MAX] = {}; const char *p = source; char *q = NULL; const char *end = source + strlen(source); if (*p != '/') { // source must start with '/' return; } // Get next '/' q = strchr(p + 1, '/'); if (q == NULL) { PLUGIN_LOGI("path \' %s \' without extra slash, ignore it", source); return; } if (q == end - 1) { PLUGIN_LOGI("path \' %s \' ends with slash, ignore it", source); return; } // OK, now get sub dir and combine it with target int ret = snprintf_s(targetFullPath, PATH_MAX, PATH_MAX - 1, "%s%s", strcmp(target, "/") == 0 ? "" : target, q); if (ret == -1) { PLUGIN_LOGE("Failed to build target path"); return; } PLUGIN_LOGI("target full path is %s", targetFullPath); if (IsRegularFile(targetFullPath)) { if (mount(source, targetFullPath, NULL, MS_BIND, NULL) != 0) { PLUGIN_LOGE("Failed to bind mount %s to %s, err = %d", source, targetFullPath, errno); } else { PLUGIN_LOGI("Bind mount %s to %s done", source, targetFullPath); } } else { if (!IsExistFile(targetFullPath)) { if (symlink(source, targetFullPath) < 0) { PLUGIN_LOGE("Failed to link %s to %s, err = %d", source, targetFullPath, errno); } } else { PLUGIN_LOGW("%s without expected type, skip overlay", targetFullPath); } } } ENG_STATIC void DebugFilesOverlay(const char *source, const char *target) { DIR *dir = NULL; struct dirent *de = NULL; if ((dir = opendir(source)) == NULL) { PLUGIN_LOGE("Open path \' %s \' failed. err = %d", source, errno); return; } int dfd = dirfd(dir); char srcPath[PATH_MAX] = {}; while ((de = readdir(dir)) != NULL) { if (de->d_name[0] == '.') { continue; } if (snprintf_s(srcPath, PATH_MAX, PATH_MAX - 1, "%s/%s",source, de->d_name) == -1) { PLUGIN_LOGE("Failed to build path for overlaying"); break; } // Determine file type struct stat st = {}; if (fstatat(dfd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { continue; } if (S_ISDIR(st.st_mode)) { DebugFilesOverlay(srcPath, target); } else if (S_ISREG(st.st_mode)) { BindMountFile(srcPath, target); } else { // Ignore any other file types PLUGIN_LOGI("Ignore %s while overlaying", srcPath); } } closedir(dir); dir = NULL; } ENG_STATIC void EngineerOverlay(void) { PLUGIN_LOGI("system overlay..."); DebugFilesOverlay("/eng_system", "/"); PLUGIN_LOGI("vendor overlay..."); DebugFilesOverlay("/eng_chipset", "/chipset"); } MODULE_CONSTRUCTOR(void) { PLUGIN_LOGI("Start eng mode now ..."); MountEngPartitions(); EngineerOverlay(); }