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 }