• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 <ctype.h>
17 #include <libgen.h>
18 #include <limits.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdbool.h>
22 #include <sys/mount.h>
23 #include <sys/types.h>
24 #include "beget_ext.h"
25 #include "fs_manager/fs_manager.h"
26 #include "init_utils.h"
27 #include "securec.h"
28 
29 #ifdef __cplusplus
30 #if __cplusplus
31 extern "C" {
32 #endif
33 #endif
34 
35 struct FsManagerFlags {
36     char *name;
37     unsigned int flags;
38 };
39 
40 struct MountFlags {
41     char *name;
42     unsigned long flags;
43 };
44 
45 static char *g_fscryptPolicy = NULL;
46 
ConvertFlags(char * flagBuffer)47 static unsigned int ConvertFlags(char *flagBuffer)
48 {
49     static struct FsManagerFlags fsFlags[] = {
50         {"check", FS_MANAGER_CHECK},
51         {"wait", FS_MANAGER_WAIT},
52         {"required", FS_MANAGER_REQUIRED},
53         {"nofail", FS_MANAGER_NOFAIL},
54 #ifdef SUPPORT_HVB
55         {"hvb", FS_MANAGER_HVB},
56 #endif
57     };
58 
59     BEGET_CHECK_RETURN_VALUE(flagBuffer != NULL && *flagBuffer != '\0', 0); // No valid flags.
60     int flagCount = 0;
61     unsigned int flags = 0;
62     const int maxCount = 3;
63     char **vector = SplitStringExt(flagBuffer, ",", &flagCount, maxCount);
64     BEGET_CHECK_RETURN_VALUE(vector != NULL && flagCount != 0, 0);
65     for (size_t i = 0; i < ARRAY_LENGTH(fsFlags); i++) {
66         for (int j = 0; j < flagCount; j++) {
67             if (strcmp(fsFlags[i].name, vector[j]) == 0) {
68                 flags |= fsFlags[i].flags;
69             }
70         }
71     }
72     FreeStringVector(vector, flagCount);
73     return flags;
74 }
75 
AddToFstab(Fstab * fstab,FstabItem * item)76 static int AddToFstab(Fstab *fstab, FstabItem *item)
77 {
78     if (fstab == NULL || item == NULL) {
79         return -1;
80     }
81     if (fstab->head != NULL) {
82         item->next = fstab->head->next;
83         fstab->head->next = item;
84     } else {
85         fstab->head = item;
86     }
87     return 0;
88 }
89 
ReleaseFstabItem(FstabItem * item)90 void ReleaseFstabItem(FstabItem *item)
91 {
92     if (item != NULL) {
93         if (item->deviceName != NULL) {
94             free(item->deviceName);
95             item->deviceName = NULL;
96         }
97 
98         if (item->mountPoint != NULL) {
99             free(item->mountPoint);
100             item->mountPoint = NULL;
101         }
102 
103         if (item->fsType != NULL) {
104             free(item->fsType);
105             item->fsType = NULL;
106         }
107 
108         if (item->mountOptions != NULL) {
109             free(item->mountOptions);
110             item->mountOptions = NULL;
111         }
112 
113         free(item);
114     }
115 }
116 
ReleaseFstab(Fstab * fstab)117 void ReleaseFstab(Fstab *fstab)
118 {
119     if (fstab != NULL) {
120         FstabItem *item = fstab->head;
121         while (item != NULL) {
122             FstabItem *tmp = item->next;
123             ReleaseFstabItem(item);
124             item = tmp;
125         }
126         free(fstab);
127         fstab = NULL;
128     }
129 }
130 
ParseFstabPerLine(char * str,Fstab * fstab,bool procMounts,const char * separator)131 int ParseFstabPerLine(char *str, Fstab *fstab, bool procMounts, const char *separator)
132 {
133     BEGET_CHECK_RETURN_VALUE(str != NULL && fstab != NULL, -1);
134     char *rest = NULL;
135     FstabItem *item = NULL;
136     char *p = NULL;
137 
138     if (separator == NULL || *separator == '\0') {
139         BEGET_LOGE("Invalid separator for parsing fstab");
140         return -1;
141     }
142 
143     if ((item = (FstabItem *)calloc(1, sizeof(FstabItem))) == NULL) {
144         errno = ENOMEM;
145         BEGET_LOGE("Allocate memory for FS table item failed, err = %d", errno);
146         return -1;
147     }
148 
149     do {
150         if ((p = strtok_r(str, separator, &rest)) == NULL) {
151             BEGET_LOGE("Failed to parse block device.");
152             break;
153         }
154         item->deviceName = strdup(p);
155 
156         if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
157             BEGET_LOGE("Failed to parse mount point.");
158             break;
159         }
160         item->mountPoint = strdup(p);
161 
162         if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
163             BEGET_LOGE("Failed to parse fs type.");
164             break;
165         }
166         item->fsType = strdup(p);
167 
168         if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
169             BEGET_LOGE("Failed to parse mount options.");
170             break;
171         }
172         item->mountOptions = strdup(p);
173 
174         if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
175             BEGET_LOGE("Failed to parse fs manager flags.");
176             break;
177         }
178         // @fsManagerFlags only for fstab
179         // Ignore it if we read from /proc/mounts
180         if (!procMounts) {
181             item->fsManagerFlags = ConvertFlags(p);
182         } else {
183             item->fsManagerFlags = 0;
184         }
185         return AddToFstab(fstab, item);
186     } while (0);
187 
188     ReleaseFstabItem(item);
189     item = NULL;
190     return -1;
191 }
192 
ReadFstabFromFile(const char * file,bool procMounts)193 Fstab *ReadFstabFromFile(const char *file, bool procMounts)
194 {
195     char *line = NULL;
196     size_t allocn = 0;
197     ssize_t readn = 0;
198     Fstab *fstab = NULL;
199 
200     FILE *fp = NULL;
201     char *realPath = GetRealPath(file);
202     if (realPath != NULL) {
203         fp = fopen(realPath, "r");
204         free(realPath);
205     } else {
206         fp = fopen(file, "r"); // no file system, can not get real path
207     }
208     if (fp == NULL) {
209         BEGET_LOGE("Open %s failed, err = %d", file, errno);
210         return NULL;
211     }
212 
213     if ((fstab = (Fstab *)calloc(1, sizeof(Fstab))) == NULL) {
214         BEGET_LOGE("Allocate memory for FS table failed, err = %d", errno);
215         fclose(fp);
216         fp = NULL;
217         return NULL;
218     }
219 
220     // Record line number of fstab file
221     size_t ln = 0;
222     while ((readn = getline(&line, &allocn, fp)) != -1) {
223         char *p = NULL;
224         ln++;
225         if (line[readn - 1] == '\n') {
226             line[readn - 1] = '\0';
227         }
228         p = line;
229         while (isspace(*p)) {
230             p++;
231         }
232 
233         if (*p == '\0' || *p == '#') {
234             continue;
235         }
236 
237         if (ParseFstabPerLine(p, fstab, procMounts, " \t") < 0) {
238             if (errno == ENOMEM) {
239                 // Ran out of memory, there is no reason to continue.
240                 break;
241             }
242             // If one line in fstab file parsed with a failure. just give a warning
243             // and skip it.
244             BEGET_LOGW("Cannot parse file \" %s \" at line %zu. skip it", file, ln);
245             continue;
246         }
247     }
248     if (line != NULL) {
249         free(line);
250     }
251     (void)fclose(fp);
252     fp = NULL;
253     return fstab;
254 }
255 
FindFstabItemForMountPoint(Fstab fstab,const char * mp)256 FstabItem *FindFstabItemForMountPoint(Fstab fstab, const char *mp)
257 {
258     FstabItem *item = NULL;
259     if (mp != NULL) {
260         for (item = fstab.head; item != NULL; item = item->next) {
261             if ((item->mountPoint != NULL) && (strcmp(item->mountPoint, mp) == 0)) {
262                 break;
263             }
264         }
265     }
266     return item;
267 }
268 
FindFstabItemForPath(Fstab fstab,const char * path)269 FstabItem *FindFstabItemForPath(Fstab fstab, const char *path)
270 {
271     FstabItem *item = NULL;
272 
273     if (path == NULL || *path != '/') {
274         return NULL;
275     }
276 
277     char tmp[PATH_MAX] = {0};
278     char *dir = NULL;
279     if (strncpy_s(tmp, PATH_MAX - 1,  path, strlen(path)) != EOK) {
280         BEGET_LOGE("Failed to copy path.");
281         return NULL;
282     }
283 
284     dir = tmp;
285     while (true) {
286         item = FindFstabItemForMountPoint(fstab, dir);
287         if (item != NULL) {
288             break;
289         }
290         dir = dirname(dir);
291         // Reverse walk through path and met "/", just quit.
292         if (dir == NULL || strcmp(dir, "/") == 0) {
293             break;
294         }
295     }
296     return item;
297 }
298 
GetFstabFile(char * fileName,size_t size)299 static char *GetFstabFile(char *fileName, size_t size)
300 {
301     if (InUpdaterMode() == 1) {
302         if (strncpy_s(fileName, size, "/etc/fstab.updater", strlen("/etc/fstab.updater")) != 0) {
303             BEGET_LOGE("Failed strncpy_s err=%d", errno);
304             return NULL;
305         }
306     } else {
307         char hardware[MAX_BUFFER_LEN] = {0};
308         char *buffer = ReadFileData("/proc/cmdline");
309         if (buffer == NULL) {
310             BEGET_LOGE("Failed to read \"/proc/cmdline\"");
311             return NULL;
312         }
313         int ret = GetProcCmdlineValue("hardware", buffer, hardware, MAX_BUFFER_LEN);
314         free(buffer);
315         if (ret != 0) {
316             BEGET_LOGE("Failed get hardware from cmdline");
317             return NULL;
318         }
319         if (snprintf_s(fileName, size, size - 1, "/vendor/etc/fstab.%s", hardware) == -1) {
320             BEGET_LOGE("Failed to build fstab file, err=%d", errno);
321             return NULL;
322         }
323     }
324     BEGET_LOGI("fstab file is %s", fileName);
325     return fileName;
326 }
327 
GetBlockDeviceByMountPoint(const char * mountPoint,const Fstab * fstab,char * deviceName,int nameLen)328 int GetBlockDeviceByMountPoint(const char *mountPoint, const Fstab *fstab, char *deviceName, int nameLen)
329 {
330     if (fstab == NULL || mountPoint == NULL || *mountPoint == '\0' || deviceName == NULL) {
331         return -1;
332     }
333     FstabItem *item = FindFstabItemForMountPoint(*fstab, mountPoint);
334     if (item == NULL) {
335         BEGET_LOGE("Failed to get fstab item from mount point \" %s \"", mountPoint);
336         return -1;
337     }
338     if (strncpy_s(deviceName, nameLen, item->deviceName, strlen(item->deviceName)) != 0) {
339         BEGET_LOGE("Failed to copy block device name, err=%d", errno);
340         return -1;
341     }
342     return 0;
343 }
344 
GetBlockDeviceByName(const char * deviceName,const Fstab * fstab,char * miscDev,size_t size)345 int GetBlockDeviceByName(const char *deviceName, const Fstab *fstab, char* miscDev, size_t size)
346 {
347     for (FstabItem *item = fstab->head; item != NULL; item = item->next) {
348         if (strstr(item->deviceName, deviceName) != NULL) {
349             BEGET_CHECK_RETURN_VALUE(strcpy_s(miscDev, size, item->deviceName) != 0, 0);
350         }
351     }
352     return -1;
353 }
354 
355 static const struct MountFlags MOUNT_FLAGS[] = {
356     { "noatime", MS_NOATIME },
357     { "noexec", MS_NOEXEC },
358     { "nosuid", MS_NOSUID },
359     { "nodev", MS_NODEV },
360     { "nodiratime", MS_NODIRATIME },
361     { "ro", MS_RDONLY },
362     { "rw", 0 },
363     { "sync", MS_SYNCHRONOUS },
364     { "remount", MS_REMOUNT },
365     { "bind", MS_BIND },
366     { "rec", MS_REC },
367     { "unbindable", MS_UNBINDABLE },
368     { "private", MS_PRIVATE },
369     { "slave", MS_SLAVE },
370     { "shared", MS_SHARED },
371     { "defaults", 0 },
372 };
373 
IsDefaultMountFlags(const char * str)374 static bool IsDefaultMountFlags(const char *str)
375 {
376     bool isDefault = false;
377 
378     if (str != NULL) {
379         for (size_t i = 0; i < ARRAY_LENGTH(MOUNT_FLAGS); i++) {
380             if (strcmp(str, MOUNT_FLAGS[i].name) == 0) {
381                 isDefault = true;
382             }
383         }
384     }
385     return isDefault;
386 }
387 
ParseDefaultMountFlag(const char * str)388 static unsigned long ParseDefaultMountFlag(const char *str)
389 {
390     unsigned long flags = 0;
391 
392     if (str != NULL) {
393         for (size_t i = 0; i < ARRAY_LENGTH(MOUNT_FLAGS); i++) {
394             if (strcmp(str, MOUNT_FLAGS[i].name) == 0) {
395                 flags = MOUNT_FLAGS[i].flags;
396                 break;
397             }
398         }
399     }
400     return flags;
401 }
402 
IsFscryptOption(const char * option)403 static bool IsFscryptOption(const char *option)
404 {
405     if (!option) {
406         return false;
407     }
408     char *fscryptPre = "fscrypt=";
409     if (strncmp(option, fscryptPre, strlen(fscryptPre)) == 0) {
410         return true;
411     }
412     return false;
413 }
414 
StoreFscryptPolicy(const char * option)415 static void StoreFscryptPolicy(const char *option)
416 {
417     if (option == NULL) {
418         return;
419     }
420     if (g_fscryptPolicy != NULL) {
421         BEGET_LOGW("StoreFscryptPolicy:inited policy is not empty");
422         free(g_fscryptPolicy);
423     }
424     g_fscryptPolicy = strdup(option);
425     if (g_fscryptPolicy == NULL) {
426         BEGET_LOGE("StoreFscryptPolicy:no memory");
427         return;
428     }
429     BEGET_LOGI("StoreFscryptPolicy:store fscrypt policy, %s", option);
430 }
431 
LoadFscryptPolicy(char * buf,size_t size)432 int LoadFscryptPolicy(char *buf, size_t size)
433 {
434     BEGET_LOGI("LoadFscryptPolicy start");
435     if (buf == NULL || g_fscryptPolicy == NULL) {
436         BEGET_LOGE("LoadFscryptPolicy:buf or fscrypt policy is empty");
437         return -ENOMEM;
438     }
439     if (size == 0) {
440         BEGET_LOGE("LoadFscryptPloicy:size is invalid");
441         return -EINVAL;
442     }
443     if (strcpy_s(buf, size, g_fscryptPolicy) != 0) {
444         BEGET_LOGE("loadFscryptPolicy:strcmp failed, error = %d", errno);
445         return -EFAULT;
446     }
447     free(g_fscryptPolicy);
448     g_fscryptPolicy = NULL;
449     BEGET_LOGI("LoadFscryptPolicy success");
450 
451     return 0;
452 }
453 
GetMountFlags(char * mountFlag,char * fsSpecificData,size_t fsSpecificDataSize,const char * mountPoint)454 unsigned long GetMountFlags(char *mountFlag, char *fsSpecificData, size_t fsSpecificDataSize,
455     const char *mountPoint)
456 {
457     unsigned long flags = 0;
458     BEGET_CHECK_RETURN_VALUE(mountFlag != NULL && fsSpecificData != NULL, 0);
459     int flagCount = 0;
460     // Why max count of mount flags is 15?
461     // There are lots for mount flags defined in sys/mount.h
462     // But we only support to parse 15 in @ParseDefaultMountFlags() function
463     // So set default mount flag number to 15.
464     // If the item configured in fstab contains flag over than 15,
465     // @SplitStringExt can handle it and parse them all. but the parse function will drop it.
466     const int maxCount = 15;
467     char **flagsVector = SplitStringExt(mountFlag, ",", &flagCount, maxCount);
468 
469     if (flagsVector == NULL || flagCount == 0) {
470         // No flags or something wrong in SplitStringExt,just return.
471         return 0;
472     }
473 
474     for (int i = 0; i < flagCount; i++) {
475         char *p = flagsVector[i];
476         if (IsDefaultMountFlags(p)) {
477             flags |= ParseDefaultMountFlag(p);
478         } else {
479             if (IsFscryptOption(p) &&
480                 !strncmp(mountPoint, "/data", strlen("/data"))) {
481                 StoreFscryptPolicy(p + strlen("fscrypt="));
482                 continue;
483             }
484             if (strncat_s(fsSpecificData, fsSpecificDataSize - 1, p, strlen(p)) != EOK) {
485                 BEGET_LOGW("Failed to append mount flag \" %s \", ignore it.", p);
486                 continue;
487             }
488             if (i == flagCount - 1) { // last flags, do not need to append ','
489                 break;
490             }
491             // Combined each mount flag with ','
492             if (strncat_s(fsSpecificData, fsSpecificDataSize - 1, ",", 1) != EOK) {
493                 BEGET_LOGW("Failed to append comma");
494                 break; // If cannot add ',' to the end of flags, there is not reason to continue.
495             }
496         }
497     }
498 
499     FreeStringVector(flagsVector, flagCount);
500     return flags;
501 }
502 
GetBlockDevicePath(const char * partName,char * path,size_t size)503 int GetBlockDevicePath(const char *partName, char *path, size_t size)
504 {
505     BEGET_CHECK_RETURN_VALUE(partName != NULL && path != NULL, -1);
506     Fstab *fstab = LoadFstabFromCommandLine();
507     if (fstab == NULL) {
508         BEGET_LOGI("fstab not found from cmdline, try to get it from file");
509         char *fstabFile = GetFstabFile(path, size);
510         BEGET_CHECK_RETURN_VALUE(fstabFile != NULL, -1);
511         fstab = ReadFstabFromFile(fstabFile, false);
512     }
513     BEGET_CHECK_RETURN_VALUE(fstab != NULL, -1);
514     int ret = GetBlockDeviceByMountPoint(partName, fstab, path, size);
515     BEGET_INFO_CHECK(ret == 0, ret = GetBlockDeviceByName(partName, fstab, path, size),
516         "Mount point not found, try to get path by device name.");
517     ReleaseFstab(fstab);
518     return ret;
519 }
520 
521 #define OHOS_REQUIRED_MOUNT_PREFIX "ohos.required_mount."
522 /*
523  * Fstab includes block device node, mount point, file system type, MNT_ Flags and options.
524  * We separate them by spaces in fstab.required file, but the separator is '@' in CmdLine.
525  * The prefix "ohos.required_mount." is the flag of required fstab information in CmdLine.
526  * Format as shown below:
527  * <block device>@<mount point>@<fstype>@<mount options>@<fstab options>
528  * e.g.
529  * ohos.required_mount.system=/dev/block/xxx/by-name/system@/usr@ext4@ro,barrier=1@wait,required
530  */
ParseRequiredMountInfo(const char * item,Fstab * fstab)531 static int ParseRequiredMountInfo(const char *item, Fstab *fstab)
532 {
533     char mountOptions[MAX_BUFFER_LEN] = {};
534     char partName[NAME_SIZE] = {};
535     // Sanity checks
536     BEGET_CHECK(!(item == NULL || *item == '\0' || fstab == NULL), return -1);
537 
538     char *p = NULL;
539     if ((p = strstr(item, "=")) != NULL) {
540         const char *q = item + strlen(OHOS_REQUIRED_MOUNT_PREFIX); // Get partition name
541         BEGET_CHECK(!(q == NULL || *q == '\0' || (p - q) <= 0), return -1);
542         BEGET_ERROR_CHECK(strncpy_s(partName, NAME_SIZE -1, q, p - q) == EOK,
543             return -1, "Failed to copy required partition name");
544         p++; // skip '='
545         BEGET_ERROR_CHECK(strncpy_s(mountOptions, MAX_BUFFER_LEN -1, p, strlen(p)) == EOK,
546             return -1, "Failed to copy required mount info: %s", item);
547     }
548     BEGET_LOGV("Mount option of partition %s is [%s]", partName, mountOptions);
549     if (ParseFstabPerLine(mountOptions, fstab, false, "@") < 0) {
550         BEGET_LOGE("Failed to parse mount options of partition \' %s \', options: %s", partName, mountOptions);
551         return -1;
552     }
553     return 0;
554 }
555 
LoadFstabFromCommandLine(void)556 Fstab* LoadFstabFromCommandLine(void)
557 {
558     Fstab *fstab = NULL;
559     char *cmdline = ReadFileData(BOOT_CMD_LINE);
560     bool isDone = false;
561 
562     BEGET_ERROR_CHECK(cmdline != NULL, return NULL, "Read from \'/proc/cmdline\' failed, err = %d", errno);
563     TrimTail(cmdline, '\n');
564     BEGET_ERROR_CHECK((fstab = (Fstab *)calloc(1, sizeof(Fstab))) != NULL, return NULL,
565         "Allocate memory for FS table failed, err = %d", errno);
566     char *start = cmdline;
567     char *end = start + strlen(cmdline);
568     while (start < end) {
569         char *token = strstr(start, " ");
570         if (token == NULL) {
571             break;
572         }
573 
574         // Startswith " "
575         if (token == start) {
576             start++;
577             continue;
578         }
579         *token = '\0';
580         if (strncmp(start, OHOS_REQUIRED_MOUNT_PREFIX,
581             strlen(OHOS_REQUIRED_MOUNT_PREFIX)) != 0) {
582             start = token + 1;
583             continue;
584         }
585         isDone = true;
586         if (ParseRequiredMountInfo(start, fstab) < 0) {
587             BEGET_LOGE("Failed to parse \' %s \'", start);
588             isDone = false;
589             break;
590         }
591         start = token + 1;
592     }
593 
594     // handle last one
595     if (start < end) {
596         if (strncmp(start, OHOS_REQUIRED_MOUNT_PREFIX,
597             strlen(OHOS_REQUIRED_MOUNT_PREFIX)) == 0 &&
598             ParseRequiredMountInfo(start, fstab) < 0) {
599             BEGET_LOGE("Failed to parse \' %s \'", start);
600             isDone = false;
601         }
602     }
603 
604     if (!isDone) {
605         ReleaseFstab(fstab);
606         fstab = NULL;
607     }
608     free(cmdline);
609     return fstab;
610 }
611 #ifdef __cplusplus
612 #if __cplusplus
613 }
614 #endif
615 #endif
616