• 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 "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