1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "init_eng.h" 17 18#include <dirent.h> 19#include <limits.h> 20#include <sys/mount.h> 21 22#include "plugin_adapter.h" 23#include "init_cmds.h" 24#include "init_utils.h" 25#include "init_module_engine.h" 26#include "securec.h" 27 28#define ENG_SYSTEM_DEVICE_PATH "/dev/block/by-name/eng_system" 29#define ENG_CHIPSET_DEVICE_PATH "/dev/block/by-name/eng_chipset" 30 31ENG_STATIC bool IsFileExistWithType(const char *file, FileType type) 32{ 33 bool isExist = false; 34 struct stat st = {}; 35 if (lstat(file, &st) == 0) { 36 switch (type) { 37 case TYPE_DIR: 38 if (S_ISDIR(st.st_mode)) { 39 isExist = true; 40 } 41 break; 42 case TYPE_REG: 43 if (S_ISREG(st.st_mode)) { 44 isExist = true; 45 } 46 break; 47 case TYPE_LINK: 48 if (S_ISLNK(st.st_mode)) { 49 isExist = true; 50 } 51 break; 52 case TYPE_ANY: // fallthrough 53 default: 54 isExist = true; 55 break; 56 } 57 } 58 return isExist; 59} 60 61static bool IsRegularFile(const char *file) 62{ 63 return file == NULL ? false : IsFileExistWithType(file, TYPE_REG); 64} 65 66static bool IsExistFile(const char *file) 67{ 68 return file == NULL ? false : IsFileExistWithType(file, TYPE_ANY); 69} 70 71ENG_STATIC void BuildMountCmd(char *buffer, size_t len, const char *mp, const char *dev, const char *fstype) 72{ 73 int ret = snprintf_s(buffer, len, len - 1, "%s %s %s ro barrier=1", 74 fstype, dev, mp); 75 if (ret == -1) { 76 *buffer = '\0'; 77 } 78} 79 80ENG_STATIC void MountEngPartitions(void) 81{ 82 char mountCmd[MOUNT_CMD_MAX_LEN] = {}; 83 // Mount eng_system 84 BuildMountCmd(mountCmd, MOUNT_CMD_MAX_LEN, "/eng_system", 85 "/dev/block/by-name/eng_system", "ext4"); 86 WaitForFile(ENG_SYSTEM_DEVICE_PATH, WAIT_MAX_SECOND); 87 int cmdIndex = 0; 88 (void)GetMatchCmd("mount ", &cmdIndex); 89 DoCmdByIndex(cmdIndex, mountCmd, NULL); 90 91 // Mount eng_chipset 92 BuildMountCmd(mountCmd, MOUNT_CMD_MAX_LEN, "/eng_chipset", 93 "/dev/block/by-name/eng_chipset", "ext4"); 94 WaitForFile(ENG_CHIPSET_DEVICE_PATH, WAIT_MAX_SECOND); 95 DoCmdByIndex(cmdIndex, mountCmd, NULL); 96} 97 98ENG_STATIC void BindMountFile(const char *source, const char *target) 99{ 100 char targetFullPath[PATH_MAX] = {}; 101 const char *p = source; 102 char *q = NULL; 103 const char *end = source + strlen(source); 104 105 if (*p != '/') { // source must start with '/' 106 return; 107 } 108 109 // Get next '/' 110 q = strchr(p + 1, '/'); 111 if (q == NULL) { 112 PLUGIN_LOGI("path \' %s \' without extra slash, ignore it", source); 113 return; 114 } 115 116 if (*(end - 1) == '/') { 117 PLUGIN_LOGI("path \' %s \' ends with slash, ignore it", source); 118 return; 119 } 120 // OK, now get sub dir and combine it with target 121 int ret = snprintf_s(targetFullPath, PATH_MAX, PATH_MAX - 1, "%s%s", strcmp(target, "/") == 0 ? "" : target, q); 122 if (ret == -1) { 123 PLUGIN_LOGE("Failed to build target path"); 124 return; 125 } 126 PLUGIN_LOGI("target full path is %s", targetFullPath); 127 if (IsRegularFile(targetFullPath)) { 128 if (mount(source, targetFullPath, NULL, MS_BIND, NULL) != 0) { 129 PLUGIN_LOGE("Failed to bind mount %s to %s, err = %d", source, targetFullPath, errno); 130 } else { 131 PLUGIN_LOGI("Bind mount %s to %s done", source, targetFullPath); 132 } 133 } else { 134 if (!IsExistFile(targetFullPath)) { 135 if (symlink(source, targetFullPath) < 0) { 136 PLUGIN_LOGE("Failed to link %s to %s, err = %d", source, targetFullPath, errno); 137 } 138 } else { 139 PLUGIN_LOGW("%s without expected type, skip overlay", targetFullPath); 140 } 141 } 142} 143 144ENG_STATIC void DebugFilesOverlay(const char *source, const char *target) 145{ 146 DIR *dir = NULL; 147 struct dirent *de = NULL; 148 149 if ((dir = opendir(source)) == NULL) { 150 PLUGIN_LOGE("Open path \' %s \' failed. err = %d", source, errno); 151 return; 152 } 153 int dfd = dirfd(dir); 154 char srcPath[PATH_MAX] = {}; 155 while ((de = readdir(dir)) != NULL) { 156 if (de->d_name[0] == '.') { 157 continue; 158 } 159 if (snprintf_s(srcPath, PATH_MAX, PATH_MAX - 1, "%s/%s", source, de->d_name) == -1) { 160 PLUGIN_LOGE("Failed to build path for overlaying"); 161 break; 162 } 163 164 // Determine file type 165 struct stat st = {}; 166 if (fstatat(dfd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { 167 continue; 168 } 169 if (S_ISDIR(st.st_mode)) { 170 DebugFilesOverlay(srcPath, target); 171 } else if (S_ISREG(st.st_mode)) { 172 BindMountFile(srcPath, target); 173 } else { // Ignore any other file types 174 PLUGIN_LOGI("Ignore %s while overlaying", srcPath); 175 } 176 } 177 closedir(dir); 178 dir = NULL; 179} 180 181ENG_STATIC void EngineerOverlay(void) 182{ 183 PLUGIN_LOGI("system overlay..."); 184 DebugFilesOverlay("/eng_system", "/"); 185 PLUGIN_LOGI("vendor overlay..."); 186 DebugFilesOverlay("/eng_chipset", "/chipset"); 187} 188 189MODULE_CONSTRUCTOR(void) 190{ 191 PLUGIN_LOGI("Start eng mode now ..."); 192 MountEngPartitions(); 193 EngineerOverlay(); 194} 195