• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 <errno.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <stdbool.h>
20 #include <sys/ioctl.h>
21 #include <sys/mount.h>
22 #include <sys/stat.h>
23 #include <sys/wait.h>
24 #include <unistd.h>
25 #include "beget_ext.h"
26 #include "fs_manager/fs_manager.h"
27 #include "init_utils.h"
28 #include "securec.h"
29 
30 #ifdef __cplusplus
31 #if __cplusplus
32 extern "C" {
33 #endif
34 #endif
35 
36 #define FS_MANAGER_BUFFER_SIZE 512
37 #define BLOCK_SIZE_BUFFER (64)
38 #define RESIZE_BUFFER_SIZE 1024
39 
IsSupportedFilesystem(const char * fsType)40 bool IsSupportedFilesystem(const char *fsType)
41 {
42     static const char *supportedFilesystem[] = {"ext4", "f2fs", NULL};
43 
44     bool supported = false;
45     int index = 0;
46     if (fsType != NULL) {
47         while (supportedFilesystem[index] != NULL) {
48             if (strcmp(supportedFilesystem[index++], fsType) == 0) {
49                 supported = true;
50                 break;
51             }
52         }
53     }
54     return supported;
55 }
56 
ExecCommand(int argc,char ** argv)57 static int ExecCommand(int argc, char **argv)
58 {
59     if (argc == 0 || argv == NULL || argv[0] == NULL) {
60         return -1;
61     }
62     pid_t pid = fork();
63     if (pid < 0) {
64         BEGET_LOGE("Fork new process to format failed: %d", errno);
65         return -1;
66     }
67     if (pid == 0) {
68         execv(argv[0], argv);
69         exit(-1);
70     }
71     int status;
72     waitpid(pid, &status, 0);
73     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
74         BEGET_LOGE("Command %s failed with status %d", argv[0], WEXITSTATUS(status));
75     }
76     return WEXITSTATUS(status);
77 }
78 
DoFormat(const char * devPath,const char * fsType)79 int DoFormat(const char *devPath, const char *fsType)
80 {
81     if (devPath == NULL || fsType == NULL) {
82         return -1;
83     }
84 
85     if (!IsSupportedFilesystem(fsType)) {
86         BEGET_LOGE("Do not support filesystem \" %s \"", fsType);
87         return -1;
88     }
89     int ret = 0;
90     char blockSizeBuffer[BLOCK_SIZE_BUFFER] = {0};
91     if (strcmp(fsType, "ext4") == 0) {
92         const unsigned int blockSize = 4096;
93         if (snprintf_s(blockSizeBuffer, BLOCK_SIZE_BUFFER, BLOCK_SIZE_BUFFER - 1, "%u", blockSize) == -1) {
94             BEGET_LOGE("Failed to build block size buffer");
95             return -1;
96         }
97         char *formatCmds[] = {
98             "/bin/mke2fs", "-F", "-t", (char *)fsType, "-b", blockSizeBuffer, (char *)devPath, NULL
99         };
100         int argc = ARRAY_LENGTH(formatCmds);
101         char **argv = (char **)formatCmds;
102         ret = ExecCommand(argc, argv);
103     } else if (strcmp(fsType, "f2fs") == 0) {
104         char *formatCmds[] = {
105             "/bin/make_f2fs", (char *)devPath, NULL
106         };
107         int argc = ARRAY_LENGTH(formatCmds);
108         char **argv = (char **)formatCmds;
109         ret = ExecCommand(argc, argv);
110     }
111     return ret;
112 }
113 
GetMountStatusForMountPoint(const char * mp)114 MountStatus GetMountStatusForMountPoint(const char *mp)
115 {
116     if (mp == NULL) {
117         return MOUNT_ERROR;
118     }
119     char buffer[FS_MANAGER_BUFFER_SIZE] = {0};
120     const int expectedItems = 6;
121     int count = 0;
122     char **mountItems = NULL;
123     MountStatus status = MOUNT_ERROR;
124     bool found = false;
125 
126     FILE *fp = fopen("/proc/mounts", "r");
127     if (fp == NULL) {
128         return status;
129     }
130     while (fgets(buffer, sizeof(buffer) - 1, fp) != NULL) {
131         size_t n = strlen(buffer);
132         if (buffer[n - 1] == '\n') {
133             buffer[n - 1] = '\0';
134         }
135         mountItems = SplitStringExt(buffer, " ", &count, expectedItems);
136         if (mountItems != NULL && count == expectedItems) {
137             // Second item in /proc/mounts is mount point
138             if (strcmp(mountItems[1], mp) == 0) {
139                 FreeStringVector(mountItems, count);
140                 found = true;
141                 break;
142             }
143             FreeStringVector(mountItems, count);
144         }
145     }
146     if (found == true) {
147         status = MOUNT_MOUNTED;
148     } else if (feof(fp) > 0) {
149         status = MOUNT_UMOUNTED;
150     }
151     (void)fclose(fp);
152     fp = NULL;
153     return status;
154 }
155 
DoResizeF2fs(const char * device,const unsigned long long size)156 static int DoResizeF2fs(const char* device, const unsigned long long size)
157 {
158     char *file = "/system/bin/resize.f2fs";
159     if (access(file, F_OK) != 0) {
160         BEGET_LOGE("resize.f2fs is not exists.");
161         return -1;
162     }
163 
164     int ret = 0;
165     if (size <= 0) {
166         char *cmd[] = {
167             file, "-s", (char *)device, NULL
168         };
169         int argc = ARRAY_LENGTH(cmd);
170         char **argv = (char **)cmd;
171         ret = ExecCommand(argc, argv);
172     } else {
173         unsigned long long realSize = size *
174             ((unsigned long long)RESIZE_BUFFER_SIZE * RESIZE_BUFFER_SIZE / FS_MANAGER_BUFFER_SIZE);
175         char sizeStr[RESIZE_BUFFER_SIZE] = {0};
176         sprintf_s(sizeStr, RESIZE_BUFFER_SIZE, "%llu", realSize);
177         char *cmd[] = {
178             file, "-s", "-t", sizeStr, (char *)device, NULL
179         };
180         int argc = ARRAY_LENGTH(cmd);
181         char **argv = (char **)cmd;
182         ret = ExecCommand(argc, argv);
183     }
184     BEGET_LOGI("resize.f2fs is ending.");
185     return ret;
186 }
187 
DoFsckF2fs(const char * device)188 static int DoFsckF2fs(const char* device)
189 {
190     char *file = "/system/bin/fsck.f2fs";
191     if (access(file, F_OK) != 0) {
192         BEGET_LOGE("fsck.f2fs is not exists.");
193         return -1;
194     }
195 
196     char *cmd[] = {
197         file, "-a", (char *)device, NULL
198     };
199     int argc = ARRAY_LENGTH(cmd);
200     char **argv = (char **)cmd;
201     BEGET_LOGI("fsck.f2fs is ending.");
202     return ExecCommand(argc, argv);
203 }
204 
DoResizeExt(const char * device,const unsigned long long size)205 static int DoResizeExt(const char* device, const unsigned long long size)
206 {
207     char *file = "/system/bin/resize2fs";
208     if (access(file, F_OK) != 0) {
209         BEGET_LOGE("resize2fs is not exists.");
210         return -1;
211     }
212 
213     int ret = 0;
214     if (size <= 0) {
215         char *cmd[] = {
216             file, "-f", (char *)device, NULL
217         };
218         int argc = ARRAY_LENGTH(cmd);
219         char **argv = (char **)cmd;
220         ret = ExecCommand(argc, argv);
221     } else {
222         char sizeStr[RESIZE_BUFFER_SIZE] = {0};
223         sprintf_s(sizeStr, RESIZE_BUFFER_SIZE, "%lluM", size);
224         char *cmd[] = {
225             file, "-f", (char *)device, sizeStr, NULL
226         };
227         int argc = ARRAY_LENGTH(cmd);
228         char **argv = (char **)cmd;
229         ret = ExecCommand(argc, argv);
230     }
231     BEGET_LOGI("resize2fs is ending.");
232     return ret;
233 }
234 
DoFsckExt(const char * device)235 static int DoFsckExt(const char* device)
236 {
237     char *file = "/system/bin/e2fsck";
238     if (access(file, F_OK) != 0) {
239         BEGET_LOGE("e2fsck is not exists.");
240         return -1;
241     }
242 
243     char *cmd[] = {
244         file, "-y", (char *)device, NULL
245     };
246     int argc = ARRAY_LENGTH(cmd);
247     char **argv = (char **)cmd;
248     BEGET_LOGI("e2fsck is ending.");
249     return ExecCommand(argc, argv);
250 }
251 
Mount(const char * source,const char * target,const char * fsType,unsigned long flags,const char * data)252 static int Mount(const char *source, const char *target, const char *fsType,
253     unsigned long flags, const char *data)
254 {
255     struct stat st = {};
256     int rc = -1;
257 
258     if (source == NULL || target == NULL || fsType == NULL) {
259         BEGET_LOGE("Invalid argment for mount.");
260         return -1;
261     }
262     if (stat(target, &st) != 0 && errno != ENOENT) {
263         BEGET_LOGE("Cannot get stat of \" %s \", err = %d", target, errno);
264         return -1;
265     }
266     if ((st.st_mode & S_IFMT) == S_IFLNK) { // link, delete it.
267         unlink(target);
268     }
269     if (mkdir(target, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0) {
270         if (errno != EEXIST) {
271             BEGET_LOGE("Failed to create dir \" %s \", err = %d", target, errno);
272             return -1;
273         }
274     }
275     errno = 0;
276     while ((rc = mount(source, target, fsType, flags, data)) != 0) {
277         if (errno == EAGAIN) {
278             BEGET_LOGE("Mount %s to %s failed. try again", source, target);
279             continue;
280         }
281         if (errno == EBUSY) {
282             rc = 0;
283         }
284         break;
285     }
286     return rc;
287 }
288 
MountOneItem(FstabItem * item)289 int MountOneItem(FstabItem *item)
290 {
291     if (item == NULL) {
292         return -1;
293     }
294     unsigned long mountFlags;
295     char fsSpecificData[FS_MANAGER_BUFFER_SIZE] = {0};
296 
297     mountFlags = GetMountFlags(item->mountOptions, fsSpecificData, sizeof(fsSpecificData));
298     if (!IsSupportedFilesystem(item->fsType)) {
299         BEGET_LOGE("Unsupported file system \" %s \"", item->fsType);
300         return 0;
301     }
302     if (FM_MANAGER_WAIT_ENABLED(item->fsManagerFlags)) {
303         WaitForFile(item->deviceName, WAIT_MAX_SECOND);
304     }
305 
306     if (strcmp(item->fsType, "f2fs") == 0 && strcmp(item->mountPoint, "/data") == 0) {
307         int ret = DoResizeF2fs(item->deviceName, 0);
308         if (ret != 0) {
309             BEGET_LOGE("Failed to resize.f2fs dir %s , ret = %d", item->deviceName, ret);
310         }
311 
312         ret = DoFsckF2fs(item->deviceName);
313         if (ret != 0) {
314             BEGET_LOGE("Failed to fsck.f2fs dir %s , ret = %d", item->deviceName, ret);
315         }
316     } else if (strcmp(item->fsType, "ext4") == 0 && strcmp(item->mountPoint, "/data") == 0) {
317         int ret = DoResizeExt(item->deviceName, 0);
318         if (ret != 0) {
319             BEGET_LOGE("Failed to resize2fs dir %s , ret = %d", item->deviceName, ret);
320         }
321         ret = DoFsckExt(item->deviceName);
322         if (ret != 0) {
323             BEGET_LOGE("Failed to e2fsck dir %s , ret = %d", item->deviceName, ret);
324         }
325     }
326 
327     int rc = Mount(item->deviceName, item->mountPoint, item->fsType, mountFlags, fsSpecificData);
328     if (rc != 0) {
329         BEGET_LOGE("Mount %s to %s failed %d", item->deviceName, item->mountPoint, errno);
330     } else {
331         BEGET_LOGI("Mount %s to %s successful", item->deviceName, item->mountPoint);
332     }
333     return rc;
334 }
335 
CheckRequiredAndMount(FstabItem * item,bool required)336 int CheckRequiredAndMount(FstabItem *item, bool required)
337 {
338     int rc = 0;
339     if (item == NULL) {
340         return -1;
341     }
342     if (required) { // Mount partition during first startup.
343         if (FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
344             rc = MountOneItem(item);
345         }
346     } else { // Mount partition during second startup.
347         if (!FM_MANAGER_REQUIRED_ENABLED(item->fsManagerFlags)) {
348             rc = MountOneItem(item);
349         }
350     }
351     return rc;
352 }
353 
MountAllWithFstab(const Fstab * fstab,bool required)354 int MountAllWithFstab(const Fstab *fstab, bool required)
355 {
356     if (fstab == NULL) {
357         return -1;
358     }
359 
360     FstabItem *item = NULL;
361     int rc = -1;
362     for (item = fstab->head; item != NULL; item = item->next) {
363         rc = CheckRequiredAndMount(item, required);
364         if (required && (rc < 0)) { // Init fail to mount in the first stage and exit directly.
365             break;
366         }
367     }
368     return rc;
369 }
370 
MountAllWithFstabFile(const char * fstabFile,bool required)371 int MountAllWithFstabFile(const char *fstabFile, bool required)
372 {
373     if (fstabFile == NULL || *fstabFile == '\0') {
374         return -1;
375     }
376     Fstab *fstab = NULL;
377     if ((fstab = ReadFstabFromFile(fstabFile, false)) == NULL) {
378         BEGET_LOGE("[fs_manager][error] Read fstab file \" %s \" failed\n", fstabFile);
379         return -1;
380     }
381 
382     int rc = MountAllWithFstab(fstab, required);
383     ReleaseFstab(fstab);
384     fstab = NULL;
385     return rc;
386 }
387 
UmountAllWithFstabFile(const char * fstabFile)388 int UmountAllWithFstabFile(const char *fstabFile)
389 {
390     if (fstabFile == NULL || *fstabFile == '\0') {
391         return -1;
392     }
393     Fstab *fstab = NULL;
394     if ((fstab = ReadFstabFromFile(fstabFile, false)) == NULL) {
395         BEGET_LOGE("Read fstab file \" %s \" failed.", fstabFile);
396         return -1;
397     }
398 
399     FstabItem *item = NULL;
400     int rc = -1;
401     for (item = fstab->head; item != NULL; item = item->next) {
402         BEGET_LOGI("Umount %s.", item->mountPoint);
403         MountStatus status = GetMountStatusForMountPoint(item->mountPoint);
404         if (status == MOUNT_ERROR) {
405             BEGET_LOGW("Cannot get mount status of mount point \" %s \"", item->mountPoint);
406             continue; // Cannot get mount status, just ignore it and try next one.
407         } else if (status == MOUNT_UMOUNTED) {
408             BEGET_LOGI("Mount point \" %s \" already unmounted. device path: %s, fs type: %s.",
409                 item->mountPoint, item->deviceName, item->fsType);
410             continue;
411         } else {
412             rc = umount(item->mountPoint);
413             if (rc == -1) {
414                 BEGET_LOGE("Umount %s failed, device path: %s, fs type: %s, err = %d.",
415                     item->mountPoint, item->deviceName, item->fsType, errno);
416             } else {
417                 BEGET_LOGE("Umount %s successfully.", item->mountPoint);
418             }
419         }
420     }
421     ReleaseFstab(fstab);
422     fstab = NULL;
423     return rc;
424 }
425 #ifdef __cplusplus
426 #if __cplusplus
427 }
428 #endif
429 #endif
430