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 "fs_manager/fs_manager.h"
27 #include "securec.h"
28
29 #define ENG_SYSTEM_DEVICE_PATH "/dev/block/by-name/eng_system"
30 #define ENG_CHIPSET_DEVICE_PATH "/dev/block/by-name/eng_chipset"
31 #define DEV_NAME_MAX_LEN 64
32
IsFileExistWithType(const char * file,FileType type)33 ENG_STATIC bool IsFileExistWithType(const char *file, FileType type)
34 {
35 bool isExist = false;
36 struct stat st = {};
37 if (lstat(file, &st) == 0) {
38 switch (type) {
39 case TYPE_DIR:
40 if (S_ISDIR(st.st_mode)) {
41 isExist = true;
42 }
43 break;
44 case TYPE_REG:
45 if (S_ISREG(st.st_mode)) {
46 isExist = true;
47 }
48 break;
49 case TYPE_LINK:
50 if (S_ISLNK(st.st_mode)) {
51 isExist = true;
52 }
53 break;
54 case TYPE_ANY: // fallthrough
55 default:
56 isExist = true;
57 break;
58 }
59 }
60 return isExist;
61 }
62
IsRegularFile(const char * file)63 static bool IsRegularFile(const char *file)
64 {
65 return file == NULL ? false : IsFileExistWithType(file, TYPE_REG);
66 }
67
IsExistFile(const char * file)68 static bool IsExistFile(const char *file)
69 {
70 return file == NULL ? false : IsFileExistWithType(file, TYPE_ANY);
71 }
72
BuildMountCmd(char * buffer,size_t len,const char * mp,const char * dev,const char * fstype)73 ENG_STATIC void BuildMountCmd(char *buffer, size_t len, const char *mp, const char *dev, const char *fstype)
74 {
75 int ret = snprintf_s(buffer, len, len - 1, "%s %s %s ro barrier=1",
76 fstype, dev, mp);
77 if (ret == -1) {
78 *buffer = '\0';
79 }
80 }
81
MountOneEngPartition(const char * partition,const char * devName)82 ENG_STATIC void MountOneEngPartition(const char *partition, const char *devName)
83 {
84 char mountCmd[MOUNT_CMD_MAX_LEN] = {};
85 BuildMountCmd(mountCmd, MOUNT_CMD_MAX_LEN, partition, devName, "ext4");
86 WaitForFile(devName, WAIT_MAX_SECOND);
87
88 int cmdIndex = 0;
89 (void)GetMatchCmd("mount ", &cmdIndex);
90 DoCmdByIndex(cmdIndex, mountCmd, NULL);
91 }
92
MountEngPartitions(void)93 ENG_STATIC void MountEngPartitions(void)
94 {
95 if (GetBootSlots() <= 1) {
96 MountOneEngPartition("/eng_system", "/dev/block/by-name/eng_system");
97 MountOneEngPartition("/eng_chipset", "/dev/block/by-name/eng_chipset");
98 return;
99 }
100 // mount AB partition
101 int currentSlot = GetCurrentSlot();
102 if (currentSlot > 0 && currentSlot <= MAX_SLOT) {
103 char slotChar = 'a' + currentSlot - 1;
104 char systemDevName[DEV_NAME_MAX_LEN] = {0};
105 int ret = snprintf_s(systemDevName, DEV_NAME_MAX_LEN, DEV_NAME_MAX_LEN - 1, "%s_%c",
106 "/dev/block/by-name/eng_system", slotChar);
107 if (ret <= 0) {
108 PLUGIN_LOGE("snprintf_s systemDevName failed");
109 return;
110 }
111 if (access(systemDevName, F_OK) != 0) {
112 MountOneEngPartition("/eng_system", "/dev/block/by-name/eng_system");
113 } else {
114 MountOneEngPartition("/eng_system", systemDevName);
115 }
116
117 char chipsetDevName[DEV_NAME_MAX_LEN] = {0};
118 ret = snprintf_s(chipsetDevName, DEV_NAME_MAX_LEN, DEV_NAME_MAX_LEN - 1, "%s_%c",
119 "/dev/block/by-name/eng_chipset", slotChar);
120 if (ret <= 0) {
121 PLUGIN_LOGE("snprintf_s chipsetDevName failed");
122 return;
123 }
124 if (access(chipsetDevName, F_OK) != 0) {
125 MountOneEngPartition("/eng_chipset", "/dev/block/by-name/eng_chipset");
126 } else {
127 MountOneEngPartition("/eng_chipset", chipsetDevName);
128 }
129 return;
130 }
131
132 MountOneEngPartition("/eng_system", "/dev/block/by-name/eng_system");
133 MountOneEngPartition("/eng_chipset", "/dev/block/by-name/eng_chipset");
134 }
135
BindMountFile(const char * source,const char * target)136 ENG_STATIC void BindMountFile(const char *source, const char *target)
137 {
138 char targetFullPath[PATH_MAX] = {};
139 const char *p = source;
140 char *q = NULL;
141 const char *end = source + strlen(source);
142
143 if (*p != '/') { // source must start with '/'
144 return;
145 }
146
147 // Get next '/'
148 q = strchr(p + 1, '/');
149 if (q == NULL) {
150 PLUGIN_LOGI("path \' %s \' without extra slash, ignore it", source);
151 return;
152 }
153
154 if (*(end - 1) == '/') {
155 PLUGIN_LOGI("path \' %s \' ends with slash, ignore it", source);
156 return;
157 }
158 // OK, now get sub dir and combine it with target
159 int ret = snprintf_s(targetFullPath, PATH_MAX, PATH_MAX - 1, "%s%s", strcmp(target, "/") == 0 ? "" : target, q);
160 if (ret == -1) {
161 PLUGIN_LOGE("Failed to build target path");
162 return;
163 }
164 PLUGIN_LOGI("target full path is %s", targetFullPath);
165 if (IsRegularFile(targetFullPath)) {
166 if (mount(source, targetFullPath, NULL, MS_BIND, NULL) != 0) {
167 PLUGIN_LOGE("Failed to bind mount %s to %s, err = %d", source, targetFullPath, errno);
168 } else {
169 PLUGIN_LOGI("Bind mount %s to %s done", source, targetFullPath);
170 }
171 } else {
172 if (!IsExistFile(targetFullPath)) {
173 if (symlink(source, targetFullPath) < 0) {
174 PLUGIN_LOGE("Failed to link %s to %s, err = %d", source, targetFullPath, errno);
175 }
176 } else {
177 PLUGIN_LOGW("%s without expected type, skip overlay", targetFullPath);
178 }
179 }
180 }
181
DebugFilesOverlay(const char * source,const char * target)182 ENG_STATIC void DebugFilesOverlay(const char *source, const char *target)
183 {
184 DIR *dir = NULL;
185 struct dirent *de = NULL;
186
187 if ((dir = opendir(source)) == NULL) {
188 PLUGIN_LOGE("Open path \' %s \' failed. err = %d", source, errno);
189 return;
190 }
191 int dfd = dirfd(dir);
192 char srcPath[PATH_MAX] = {};
193 while ((de = readdir(dir)) != NULL) {
194 if (de->d_name[0] == '.') {
195 continue;
196 }
197 if (snprintf_s(srcPath, PATH_MAX, PATH_MAX - 1, "%s/%s", source, de->d_name) == -1) {
198 PLUGIN_LOGE("Failed to build path for overlaying");
199 break;
200 }
201
202 // Determine file type
203 struct stat st = {};
204 if (fstatat(dfd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
205 continue;
206 }
207 if (S_ISDIR(st.st_mode)) {
208 DebugFilesOverlay(srcPath, target);
209 } else if (S_ISREG(st.st_mode)) {
210 BindMountFile(srcPath, target);
211 } else { // Ignore any other file types
212 PLUGIN_LOGI("Ignore %s while overlaying", srcPath);
213 }
214 }
215 closedir(dir);
216 dir = NULL;
217 }
218
EngineerOverlay(void)219 ENG_STATIC void EngineerOverlay(void)
220 {
221 PLUGIN_LOGI("system overlay...");
222 DebugFilesOverlay("/eng_system", "/");
223 PLUGIN_LOGI("vendor overlay...");
224 DebugFilesOverlay("/eng_chipset", "/chipset");
225 }
226
MODULE_CONSTRUCTOR(void)227 MODULE_CONSTRUCTOR(void)
228 {
229 PLUGIN_LOGI("Start eng mode now ...");
230 MountEngPartitions();
231 EngineerOverlay();
232 }
233