• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "switch_root.h"
23 #include "fs_manager/fs_manager.h"
24 
25 #include "erofs_mount_overlay.h"
26 
27 #define BYTE_UNIT 1024
28 #define ALIGN_BLOCK_SIZE (16 * BYTE_UNIT)
29 #define MIN_DM_SIZE (2 * BYTE_UNIT * BYTE_UNIT)
30 #define BLOCK_SIZE_UINT 4096
31 #define EXTHDR_MAGIC 0xFEEDBEEF
32 #define EXTHDR_BLKSIZE 4096
33 
34 struct extheader_v1 {
35     uint32_t magic_number;
36     uint16_t exthdr_size;
37     uint16_t bcc16;
38     uint64_t part_size;
39 };
40 
AllocDmName(const char * name,char * nameRofs,const uint64_t nameRofsLen,char * nameExt4,const uint64_t nameExt4Len)41 INIT_STATIC void AllocDmName(const char *name, char *nameRofs, const uint64_t nameRofsLen,
42     char *nameExt4, const uint64_t nameExt4Len)
43 {
44     if (snprintf_s(nameRofs, nameRofsLen, nameRofsLen - 1, "%s_erofs", name) < 0) {
45         BEGET_LOGE("Failed to copy nameRofs.");
46         return;
47     }
48 
49     if (snprintf_s(nameExt4, nameExt4Len, nameExt4Len - 1, "%s_ext4", name) < 0) {
50         BEGET_LOGE("Failed to copy nameExt4.");
51         return;
52     }
53 
54     uint64_t i = 0;
55     while (nameRofs[i] != '\0') {
56         if (nameRofs[i] == '/') {
57             nameRofs[i] = '_';
58         }
59         i++;
60     }
61     i = 0;
62     while (nameExt4[i] != '\0') {
63         if (nameExt4[i] == '/') {
64             nameExt4[i] = '_';
65         }
66         i++;
67     }
68 
69     BEGET_LOGI("alloc dm namerofs:[%s], nameext4:[%s]", nameRofs, nameExt4);
70 }
71 
LookupErofsEnd(const char * dev)72 INIT_STATIC uint64_t LookupErofsEnd(const char *dev)
73 {
74     int fd = -1;
75     fd = open(dev, O_RDONLY | O_LARGEFILE);
76     if (fd < 0) {
77         BEGET_LOGE("open dev:[%s] failed.", dev);
78         return 0;
79     }
80 
81     if (lseek(fd, EROFS_SUPER_BLOCK_START_POSITION, SEEK_SET) < 0) {
82         BEGET_LOGE("lseek dev:[%s] failed.", dev);
83         close(fd);
84         return 0;
85     }
86 
87     struct erofs_super_block sb;
88     ssize_t nbytes = read(fd, &sb, sizeof(sb));
89     if (nbytes != sizeof(sb)) {
90         BEGET_LOGE("read dev:[%s] failed.", dev);
91         close(fd);
92         return 0;
93     }
94     close(fd);
95 
96     if (sb.magic != EROFS_SUPER_MAGIC) {
97         BEGET_LOGE("dev:[%s] is not erofs system, magic is 0x%x", dev, sb.magic);
98         return 0;
99     }
100 
101     uint64_t erofsSize = (uint64_t)sb.blocks * BLOCK_SIZE_UINT;
102     return erofsSize;
103 }
104 
GetImgSize(const char * dev,uint64_t offset)105 INIT_STATIC uint64_t GetImgSize(const char *dev, uint64_t offset)
106 {
107     int fd = -1;
108     fd = open(dev, O_RDONLY | O_LARGEFILE);
109     if (fd < 0) {
110         BEGET_LOGE("open dev:[%s] failed.", dev);
111         return 0;
112     }
113 
114     if (lseek(fd, offset, SEEK_SET) < 0) {
115         BEGET_LOGE("lseek dev:[%s] failed, offset is %llu", dev, offset);
116         close(fd);
117         return 0;
118     }
119 
120     struct extheader_v1 header;
121     ssize_t nbytes = read(fd, &header, sizeof(header));
122     if (nbytes != sizeof(header)) {
123         BEGET_LOGE("read dev:[%s] failed.", dev);
124         close(fd);
125         return 0;
126     }
127     close(fd);
128 
129     if (header.magic_number != EXTHDR_MAGIC) {
130         BEGET_LOGI("dev:[%s] is not have ext path, magic is 0x%x", dev, header.magic_number);
131         return 0;
132     }
133     BEGET_LOGI("get img size [%llu]", header.part_size);
134     return header.part_size;
135 }
136 
GetFsSize(int fd)137 INIT_STATIC uint64_t GetFsSize(int fd)
138 {
139     struct stat st;
140     if (fstat(fd, &st) == -1) {
141         BEGET_LOGE("fstat failed. errno: %d", errno);
142         return 0;
143     }
144 
145     uint64_t size = 0;
146     if (S_ISBLK(st.st_mode)) {
147         if (ioctl(fd, BLKGETSIZE64, &size) == -1) {
148             BEGET_LOGE("ioctl failed. errno: %d", errno);
149             return 0;
150         }
151     } else if (S_ISREG(st.st_mode)) {
152         if (st.st_size < 0) {
153             BEGET_LOGE("st_size is not right. st_size: %lld", st.st_size);
154             return 0;
155         }
156         size = (uint64_t)st.st_size;
157     } else {
158         BEGET_LOGE("unspported type st_mode:[%llu]", st.st_mode);
159         errno = EACCES;
160         return 0;
161     }
162 
163     BEGET_LOGI("get fs size:[%llu]", size);
164     return size;
165 }
166 
GetBlockSize(const char * dev)167 INIT_STATIC uint64_t GetBlockSize(const char *dev)
168 {
169     int fd = -1;
170     fd = open(dev, O_RDONLY | O_LARGEFILE);
171     if (fd < 0) {
172         BEGET_LOGE("open dev:[%s] failed.", dev);
173         return 0;
174     }
175 
176     uint64_t blockSize = GetFsSize(fd);
177     close(fd);
178     return blockSize;
179 }
180 
181 /* 字节对齐函数,基于alignment进行字节对齐 */
AlignTo(uint64_t base,uint64_t alignment)182 INIT_STATIC uint64_t AlignTo(uint64_t base, uint64_t alignment)
183 {
184     if (alignment == 0) {
185         return base;
186     }
187     return (((base - 1) / alignment + 1) * alignment);
188 }
189 
GetMapperAddr(const char * dev,uint64_t * start,uint64_t * length)190 INIT_STATIC int GetMapperAddr(const char *dev, uint64_t *start, uint64_t *length)
191 {
192     /* 获取EROFS文件系统大小 */
193     *start = LookupErofsEnd(dev);
194     if (*start == 0) {
195         BEGET_LOGE("get erofs end failed.");
196         return -1;
197     }
198 
199     /*
200      * 获取镜像大小 当前镜像布局有2种
201      * 老布局:EROFS文件系统 + 全0数据填充 + HVB数据  老布局不存在EXTHEADER,获取到的镜像大小为0。直接基于文件系统切分
202      * 新布局:EROFS文件系统 + EXTHEADER + HVB数据   新布局存在EXTHEADER,基于EXTHEADER获取镜像大小后进行分区切分
203      */
204     uint64_t imgSize = GetImgSize(dev, *start);
205     if (imgSize > 0) {
206         *start = AlignTo(imgSize, ALIGN_BLOCK_SIZE);
207     }
208 
209     /* 获取分区大小,老分区布局:分区大小 = 镜像大小  新分区布局:分区大小 = 镜像大小 + 无镜像填充的分区空位 */
210     uint64_t totalSize = GetBlockSize(dev);
211     if (totalSize == 0) {
212         BEGET_LOGE("get block size failed.");
213         return -1;
214     }
215 
216     BEGET_LOGI("total size:[%llu], used size: [%llu], empty size:[%llu] on dev: [%s]",
217         totalSize, *start, totalSize - *start, dev);
218 
219     if (totalSize > *start) {
220         *length = totalSize - *start;
221     } else {
222         *length = 0;
223     }
224 
225     if (*length < MIN_DM_SIZE) {
226         BEGET_LOGE("empty size is too small, skip...");
227         return -1;
228     }
229 
230     return 0;
231 }
232 
ConstructLinearTarget(DmVerityTarget * target,const char * dev,uint64_t mapStart,uint64_t mapLength)233 INIT_STATIC int ConstructLinearTarget(DmVerityTarget *target, const char *dev, uint64_t mapStart, uint64_t mapLength)
234 {
235     if (target == NULL || dev == NULL) {
236         return -1;
237     }
238 
239     target->start = 0;
240     target->length = mapLength / SECTOR_SIZE;
241     target->paras = calloc(1, MAX_BUFFER_LEN);
242     if (target->paras == NULL) {
243         BEGET_LOGE("Failed to calloc target paras");
244         return -1;
245     }
246 
247     if (snprintf_s(target->paras, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, "%s %llu", dev, mapStart / SECTOR_SIZE) < 0) {
248         BEGET_LOGE("Failed to copy target paras.");
249         return -1;
250     }
251     target->paras_len = strlen(target->paras);
252     BEGET_LOGI("dev [%s], linearparas [%s], length [%s]", dev, target->paras, target->paras_len);
253     return 0;
254 }
255 
DestoryLinearTarget(DmVerityTarget * target)256 INIT_STATIC void DestoryLinearTarget(DmVerityTarget *target)
257 {
258     if (target != NULL && target->paras != NULL) {
259         free(target->paras);
260         target->paras = NULL;
261     }
262 }
263 
GetOverlayDevice(FstabItem * item,char * devRofs,const uint32_t devRofsLen,char * devExt4,const uint32_t devExt4Len)264 INIT_STATIC int GetOverlayDevice(FstabItem *item, char *devRofs, const uint32_t devRofsLen,
265     char *devExt4, const uint32_t devExt4Len)
266 {
267     uint64_t mapStart;
268     uint64_t mapLength;
269     char nameExt4[MAX_BUFFER_LEN] = {0};
270     char nameRofs[MAX_BUFFER_LEN] = {0};
271 
272     if (access(item->deviceName, 0) < 0) {
273         BEGET_LOGE("connot access dev [%s]", item->deviceName);
274         return -1;
275     }
276 
277     AllocDmName(item->mountPoint, nameRofs, MAX_BUFFER_LEN, nameExt4, MAX_BUFFER_LEN);
278 
279     if (GetMapperAddr(item->deviceName, &mapStart, &mapLength)) {
280         BEGET_LOGE("get mapper addr failed, dev is [%s]", item->deviceName);
281         return -1;
282     }
283 
284     DmVerityTarget dmRofsTarget = {0};
285     DmVerityTarget dmExt4Target = {0};
286 
287     int rc = ConstructLinearTarget(&dmRofsTarget, item->deviceName, 0, mapStart);
288     if (rc != 0) {
289         BEGET_LOGE("fs construct erofs linear target failed, dev is [%s]", item->deviceName);
290         goto exit;
291     }
292     rc = FsDmCreateLinearDevice(nameRofs, devRofs, devRofsLen, &dmRofsTarget);
293     if (rc != 0) {
294         BEGET_LOGE("fs create erofs linear device failed, dev is [%s]", item->deviceName);
295         goto exit;
296     }
297 
298     rc = ConstructLinearTarget(&dmExt4Target, item->deviceName, mapStart, mapLength);
299     if (rc != 0) {
300         BEGET_LOGE("fs construct ext4 linear target failed, dev is [%s]", item->deviceName);
301         goto exit;
302     }
303     rc = FsDmCreateLinearDevice(nameExt4, devExt4, devExt4Len, &dmExt4Target);
304     if (rc != 0) {
305         BEGET_LOGE("fs create ext4 linear device failed, dev is [%s]", item->deviceName);
306         goto exit;
307     }
308     BEGET_LOGI("get overlay device success , dev is [%s]", item->deviceName);
309 exit:
310     DestoryLinearTarget(&dmRofsTarget);
311     DestoryLinearTarget(&dmExt4Target);
312     return rc;
313 }
314 
MountRofsDevice(const char * dev,const char * mnt)315 INIT_STATIC int MountRofsDevice(const char *dev, const char *mnt)
316 {
317     int rc = 0;
318     int retryCount = 3;
319     while (retryCount-- > 0) {
320         rc = mount(dev, mnt, "erofs", MS_RDONLY, NULL);
321         if (rc && (errno != EBUSY)) {
322             BEGET_LOGI("mount erofs dev [%s] on mnt [%s] failed, retry", dev, mnt);
323             sleep(1);
324             continue;
325         }
326         break;
327     }
328 
329     return 0;
330 }
331 
MountExt4Device(const char * dev,const char * mnt,bool isFirstMount)332 int MountExt4Device(const char *dev, const char *mnt, bool isFirstMount)
333 {
334     int ret = 0;
335     char dirExt4[MAX_BUFFER_LEN] = {0};
336     char dirUpper[MAX_BUFFER_LEN] = {0};
337     char dirWork[MAX_BUFFER_LEN] = {0};
338     ret = snprintf_s(dirExt4, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, PREFIX_OVERLAY"%s", mnt);
339     if (ret < 0) {
340         BEGET_LOGE("dirExt4 copy failed errno %d.", errno);
341         return -1;
342     }
343 
344     ret = snprintf_s(dirUpper, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, PREFIX_OVERLAY"%s"PREFIX_UPPER, mnt);
345     if (ret < 0) {
346         BEGET_LOGE("dirUpper copy failed errno %d.", errno);
347         return -1;
348     }
349 
350     ret = snprintf_s(dirWork, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, PREFIX_OVERLAY"%s"PREFIX_WORK, mnt);
351     if (ret < 0) {
352         BEGET_LOGE("dirWork copy failed errno %d.", errno);
353         return -1;
354     }
355 
356     if (mkdir(dirExt4, MODE_MKDIR) && (errno != EEXIST)) {
357         BEGET_LOGE("mkdir %s failed.", dirExt4);
358         return -1;
359     }
360 
361     int retryCount = 3;
362     while (retryCount-- > 0) {
363         ret = mount(dev, dirExt4, "ext4", MS_NOATIME | MS_NODEV, NULL);
364         if (ret && (errno != EBUSY)) {
365             BEGET_LOGI("mount ext4 dev [%s] on mnt [%s] failed, retry", dev, dirExt4);
366             sleep(1);
367             continue;
368         }
369         break;
370     }
371 
372     if (isFirstMount && mkdir(dirUpper, MODE_MKDIR) && (errno != EEXIST)) {
373         BEGET_LOGE("mkdir dirUpper:%s failed.", dirUpper);
374         return -1;
375     }
376 
377     if (isFirstMount && mkdir(dirWork, MODE_MKDIR) && (errno != EEXIST)) {
378         BEGET_LOGE("mkdir dirWork:%s failed.", dirWork);
379         return -1;
380     }
381 
382     return ret;
383 }
384 
UnlinkMountPoint(const char * mountPoint)385 INIT_STATIC void UnlinkMountPoint(const char *mountPoint)
386 {
387     struct stat statInfo;
388     if (!lstat(mountPoint, &statInfo)) {
389         if ((statInfo.st_mode & S_IFMT) == S_IFLNK) {
390             unlink(mountPoint);
391         }
392     }
393 }
394 
MountPartitionDevice(FstabItem * item,const char * devRofs,const char * devExt4)395 INIT_STATIC int MountPartitionDevice(FstabItem *item, const char *devRofs, const char *devExt4)
396 {
397     UnlinkMountPoint(item->mountPoint);
398     if (mkdir(item->mountPoint, MODE_MKDIR) && (errno != EEXIST)) {
399         BEGET_LOGE("mkdir mountPoint:%s failed.errno %d", item->mountPoint, errno);
400         return -1;
401     }
402 
403     WaitForFile(devRofs, WAIT_MAX_SECOND);
404     WaitForFile(devExt4, WAIT_MAX_SECOND);
405 
406     if (MountRofsDevice(devRofs, item->mountPoint)) {
407         BEGET_LOGE("mount erofs dev [%s] on mnt [%s] failed", devRofs, item->mountPoint);
408         return -1;
409     }
410 
411     if (strcmp(item->mountPoint, "/usr") == 0) {
412         SwitchRoot("/usr");
413     }
414 
415     if (mkdir(PREFIX_LOWER, MODE_MKDIR) && (errno != EEXIST)) {
416         BEGET_LOGE("mkdir /lower failed. errno: %d", errno);
417         return -1;
418     }
419 
420     if (mkdir(PREFIX_OVERLAY, MODE_MKDIR) && (errno != EEXIST)) {
421         BEGET_LOGE("mkdir /overlay failed. errno: %d", errno);
422         return -1;
423     }
424 
425     char dirLower[MAX_BUFFER_LEN] = {0};
426     if (snprintf_s(dirLower, MAX_BUFFER_LEN, MAX_BUFFER_LEN - 1, "%s%s", PREFIX_LOWER, item->mountPoint) < 0) {
427         BEGET_LOGE("dirLower[%s]copy failed errno %d.", dirLower, errno);
428         return -1;
429     }
430 
431     if (mkdir(dirLower, MODE_MKDIR) && (errno != EEXIST)) {
432         BEGET_LOGE("mkdir dirLower[%s] failed. errno: %d", dirLower, errno);
433         return -1;
434     }
435 
436     if (MountRofsDevice(devRofs, dirLower)) {
437         BEGET_LOGE("mount erofs dev [%s] on mnt [%s] failed", devRofs, dirLower);
438         return -1;
439     }
440 
441     if (!CheckIsExt4(devExt4, 0)) {
442         BEGET_LOGI("is not ext4 devExt4 [%s] on mnt [%s]", devExt4, item->mountPoint);
443         return 0;
444     }
445 
446     BEGET_LOGI("is ext4 devExt4 [%s] on mnt [%s]", devExt4, item->mountPoint);
447     if (MountExt4Device(devExt4, item->mountPoint, false)) {
448         BEGET_LOGE("mount ext4 dev [%s] on mnt [%s] failed", devExt4, item->mountPoint);
449         return -1;
450     }
451 
452     return 0;
453 }
454 
DoMountOverlayDevice(FstabItem * item)455 int DoMountOverlayDevice(FstabItem *item)
456 {
457     char devRofs[MAX_BUFFER_LEN] = {0};
458     char devExt4[MAX_BUFFER_LEN] = {0};
459     int rc = 0;
460     rc = GetOverlayDevice(item, devRofs, MAX_BUFFER_LEN, devExt4, MAX_BUFFER_LEN);
461     if (rc) {
462         BEGET_LOGE("get overlay device failed, source [%s] target [%s]", item->deviceName, item->mountPoint);
463         return -1;
464     }
465 
466     rc = FsDmInitDmDev(devRofs, true);
467     if (rc) {
468         BEGET_LOGE("init erofs dm dev failed");
469         return -1;
470     }
471 
472     rc = FsDmInitDmDev(devExt4, true);
473     if (rc) {
474         BEGET_LOGE("init ext4 dm dev failed");
475         return -1;
476     }
477 
478     rc = MountPartitionDevice(item, devRofs, devExt4);
479     if (rc) {
480         BEGET_LOGE("init ext4 dm dev failed");
481         return -1;
482     }
483     return rc;
484 }