• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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