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