1 /*
2 * Copyright (c) 2024-2024 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 <sys/mount.h>
17 #include <sys/stat.h>
18 #include <sys/wait.h>
19 #include "securec.h"
20 #include "init_utils.h"
21 #include "fs_dm.h"
22 #include "fs_manager/fs_manager.h"
23 #include "erofs_remount_overlay.h"
24
25 #define MODEM_DRIVER_MNT_PATH "/vendor/modem/modem_driver"
26 #define MODEM_VENDOR_MNT_PATH "/vendor/modem/modem_vendor"
27 #define MODEM_FW_MNT_PATH "/vendor/modem/modem_fw"
28 #define MODEM_DRIVER_EXCHANGE_PATH "/mnt/driver_exchange"
29 #define MODEM_VENDOR_EXCHANGE_PATH "/mnt/vendor_exchange"
30 #define MODEM_FW_EXCHANGE_PATH "/mnt/fw_exchange"
31 #define REMOUNT_RESULT_PATH "/data/service/el1/startup/remount/"
32 #define REMOUNT_RESULT_FLAG "/data/service/el1/startup/remount/remount.result.done"
33
GetRemountResult(void)34 int GetRemountResult(void)
35 {
36 int fd = open(REMOUNT_RESULT_FLAG, O_RDONLY);
37 if (fd >= 0) {
38 char buff[1];
39 int ret = read(fd, buff, 1);
40 if (ret < 0) {
41 BEGET_LOGE("read remount.result.done failed errno %d", errno);
42 close(fd);
43 return REMOUNT_FAIL;
44 }
45 close(fd);
46 if (buff[0] == '0' + REMOUNT_SUCC) {
47 return REMOUNT_SUCC;
48 }
49 }
50 return REMOUNT_FAIL;
51 }
52
SetRemountResultFlag(void)53 void SetRemountResultFlag(void)
54 {
55 struct stat st;
56 int ret;
57
58 int statRet = stat(REMOUNT_RESULT_PATH, &st);
59 if (statRet != 0) {
60 ret = mkdir(REMOUNT_RESULT_PATH, MODE_MKDIR);
61 if (ret < 0 && errno != EEXIST) {
62 BEGET_LOGE("mkdir remount path failed errno %d", errno);
63 return;
64 }
65 }
66
67 int fd = open(REMOUNT_RESULT_FLAG, O_WRONLY | O_CREAT, 0644);
68 if (fd < 0) {
69 BEGET_LOGE("open remount.result.done failed errno %d", errno);
70 return;
71 }
72
73 char buff[1];
74 buff[0] = '0' + REMOUNT_SUCC;
75
76 ret = write(fd, buff, 1);
77 if (ret < 0) {
78 BEGET_LOGE("write buff failed errno %d", errno);
79 }
80 close(fd);
81 BEGET_LOGI("set remount result flag successfully");
82 }
83
Modem2Exchange(const char * modemPath,const char * exchangePath)84 static int Modem2Exchange(const char *modemPath, const char *exchangePath)
85 {
86 int ret;
87 ret = mkdir(exchangePath, MODE_MKDIR);
88 if (ret) {
89 BEGET_LOGE("mkdir %s failed.", exchangePath);
90 } else {
91 BEGET_LOGI("mkdir %s succeed.", exchangePath);
92 }
93
94 ret = mount(modemPath, exchangePath, NULL, MS_BIND | MS_RDONLY, NULL);
95 if (ret) {
96 BEGET_LOGE("bind %s to %s failed.", modemPath, exchangePath);
97 } else {
98 BEGET_LOGI("bind %s to %s succeed.", modemPath, exchangePath);
99 }
100
101 return ret;
102 }
103
Exchange2Modem(const char * modemPath,const char * exchangePath)104 static int Exchange2Modem(const char *modemPath, const char *exchangePath)
105 {
106 int ret;
107 struct stat statInfo;
108 if (lstat(exchangePath, &statInfo)) {
109 BEGET_LOGE("no exchangePath %s.", exchangePath);
110 return 0;
111 }
112
113 ret = mount(exchangePath, modemPath, NULL, MS_BIND | MS_RDONLY, NULL);
114 if (ret) {
115 BEGET_LOGE("bind %s to %s failed.", exchangePath, modemPath);
116 } else {
117 BEGET_LOGI("bind %s to %s succeed.", exchangePath, modemPath);
118 }
119
120 ret = umount(exchangePath);
121 if (ret) {
122 BEGET_LOGE("umount %s failed.", exchangePath);
123 } else {
124 BEGET_LOGI("umount %s succeed.", exchangePath);
125 }
126
127 ret = remove(exchangePath);
128 if (ret) {
129 BEGET_LOGE("remove %s failed.", exchangePath);
130 } else {
131 BEGET_LOGI("remove %s succeed.", exchangePath);
132 }
133
134 return ret;
135 }
136
OverlayRemountVendorPre(void)137 void OverlayRemountVendorPre(void)
138 {
139 struct stat statInfo;
140
141 if (!stat(MODEM_DRIVER_MNT_PATH, &statInfo)) {
142 Modem2Exchange(MODEM_DRIVER_MNT_PATH, MODEM_DRIVER_EXCHANGE_PATH);
143 }
144
145 if (!stat(MODEM_VENDOR_MNT_PATH, &statInfo)) {
146 Modem2Exchange(MODEM_VENDOR_MNT_PATH, MODEM_VENDOR_EXCHANGE_PATH);
147 }
148
149 if (!stat(MODEM_FW_MNT_PATH, &statInfo)) {
150 Modem2Exchange(MODEM_FW_MNT_PATH, MODEM_FW_EXCHANGE_PATH);
151 }
152 }
153
OverlayRemountVendorPost()154 void OverlayRemountVendorPost()
155 {
156 Exchange2Modem(MODEM_DRIVER_MNT_PATH, MODEM_DRIVER_EXCHANGE_PATH);
157 Exchange2Modem(MODEM_VENDOR_MNT_PATH, MODEM_VENDOR_EXCHANGE_PATH);
158 Exchange2Modem(MODEM_FW_MNT_PATH, MODEM_FW_EXCHANGE_PATH);
159 }
160
MountOverlayOne(const char * mnt)161 int MountOverlayOne(const char *mnt)
162 {
163 if ((strcmp(mnt, MODEM_DRIVER_MNT_PATH) == 0) || (strcmp(mnt, MODEM_VENDOR_MNT_PATH) == 0)) {
164 return 0;
165 }
166 char dirLower[MAX_BUFFER_LEN] = {0};
167 char dirUpper[MAX_BUFFER_LEN] = {0};
168 char dirWork[MAX_BUFFER_LEN] = {0};
169 char mntOpt[MAX_BUFFER_LEN] = {0};
170
171 if (strcmp(mnt, "/usr") == 0) {
172 if (snprintf_s(dirLower, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, "%s", "/system") < 0) {
173 BEGET_LOGE("copy system dirLower failed. errno %d", errno);
174 return -1;
175 }
176 } else {
177 if (snprintf_s(dirLower, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, "%s%s", PREFIX_LOWER, mnt) < 0) {
178 BEGET_LOGE("copy dirLower failed. errno %d", errno);
179 return -1;
180 }
181 }
182
183 if (snprintf_s(dirUpper, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, "%s%s%s", PREFIX_OVERLAY, mnt, PREFIX_UPPER) < 0) {
184 BEGET_LOGE("copy dirUpper failed. errno %d", errno);
185 return -1;
186 }
187
188 if (snprintf_s(dirWork, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, "%s%s%s", PREFIX_OVERLAY, mnt, PREFIX_WORK) < 0) {
189 BEGET_LOGE("copy dirWork failed. errno %d", errno);
190 return -1;
191 }
192
193 if (snprintf_s(mntOpt, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1,
194 "upperdir=%s,lowerdir=%s,workdir=%s,override_creds=off", dirUpper, dirLower, dirWork) < 0) {
195 BEGET_LOGE("copy mntOpt failed. errno %d", errno);
196 return -1;
197 }
198
199 if (strcmp(mnt, "/usr") == 0) {
200 if (mount("overlay", "/system", "overlay", 0, mntOpt)) {
201 BEGET_LOGE("mount system overlay failed. errno %d", errno);
202 return -1;
203 }
204 } else {
205 if (mount("overlay", mnt, "overlay", 0, mntOpt)) {
206 BEGET_LOGE("mount overlay fs failed. errno %d", errno);
207 return -1;
208 }
209 }
210 BEGET_LOGI("mount overlay fs success on mnt:%s", mnt);
211 return 0;
212 }
213
RemountOverlay(void)214 int RemountOverlay(void)
215 {
216 char *remountPath[] = { "/usr", "/vendor", "/sys_prod", "/chip_prod", "/preload", "/cust", "/version" };
217 for (size_t i = 0; i < ARRAY_LENGTH(remountPath); i++) {
218 struct stat statInfo;
219 char dirMnt[MAX_BUFFER_LEN] = {0};
220 if (snprintf_s(dirMnt, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, "/mnt/overlay%s/upper", remountPath[i]) < 0) {
221 BEGET_LOGE("copy dirMnt [%s] failed.", dirMnt);
222 return -1;
223 }
224
225 if (lstat(dirMnt, &statInfo)) {
226 BEGET_LOGW("dirMnt [%s] not exist.", dirMnt);
227 continue;
228 }
229
230 if (strcmp(remountPath[i], "/vendor") == 0) {
231 OverlayRemountVendorPre();
232 }
233
234 if (MountOverlayOne(remountPath[i])) {
235 BEGET_LOGE("mount overlay failed on mnt [%s].", dirMnt);
236 return -1;
237 }
238
239 if (strcmp(remountPath[i], "/vendor") == 0) {
240 OverlayRemountVendorPost();
241 }
242 }
243 return 0;
244 }