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
IsFileExistWithType(const char * file,FileType type)31 ENG_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
IsRegularFile(const char * file)61 static bool IsRegularFile(const char *file)
62 {
63 return file == NULL ? false : IsFileExistWithType(file, TYPE_REG);
64 }
65
IsExistFile(const char * file)66 static bool IsExistFile(const char *file)
67 {
68 return file == NULL ? false : IsFileExistWithType(file, TYPE_ANY);
69 }
70
BuildMountCmd(char * buffer,size_t len,const char * mp,const char * dev,const char * fstype)71 ENG_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
MountEngPartitions(void)80 ENG_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
BindMountFile(const char * source,const char * target)98 ENG_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
DebugFilesOverlay(const char * source,const char * target)144 ENG_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
EngineerOverlay(void)181 ENG_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
MODULE_CONSTRUCTOR(void)189 MODULE_CONSTRUCTOR(void)
190 {
191 PLUGIN_LOGI("Start eng mode now ...");
192 MountEngPartitions();
193 EngineerOverlay();
194 }
195