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 <ctype.h>
17 #include <fcntl.h>
18 #include <libgen.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdbool.h>
23 #include <sys/mount.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include "beget_ext.h"
28 #include "fs_manager/fs_manager.h"
29 #include "init_utils.h"
30 #include "securec.h"
31
32 #ifdef __cplusplus
33 #if __cplusplus
34 extern "C" {
35 #endif
36 #endif
37
38 struct FsManagerFlags {
39 char *name;
40 unsigned int flags;
41 };
42
43 struct MountFlags {
44 char *name;
45 unsigned long flags;
46 };
47
ConvertFlags(char * flagBuffer)48 unsigned int ConvertFlags(char *flagBuffer)
49 {
50 static struct FsManagerFlags fsFlags[] = {
51 {"check", FS_MANAGER_CHECK},
52 {"wait", FS_MANAGER_WAIT},
53 {"required", FS_MANAGER_REQUIRED},
54 };
55
56 BEGET_CHECK_RETURN_VALUE(flagBuffer != NULL && *flagBuffer != '\0', 0); // No valid flags.
57 int flagCount = 0;
58 unsigned int flags = 0;
59 const int maxCount = 3;
60 char **vector = SplitStringExt(flagBuffer, ",", &flagCount, maxCount);
61 BEGET_CHECK_RETURN_VALUE(vector != NULL && flagCount != 0, 0);
62 for (size_t i = 0; i < ARRAY_LENGTH(fsFlags); i++) {
63 for (int j = 0; j < flagCount; j++) {
64 if (strcmp(fsFlags[i].name, vector[j]) == 0) {
65 flags |= fsFlags[i].flags;
66 }
67 }
68 }
69 FreeStringVector(vector, flagCount);
70 return flags;
71 }
72
AddToFstab(Fstab * fstab,FstabItem * item)73 static void AddToFstab(Fstab *fstab, FstabItem *item)
74 {
75 if (fstab == NULL || item == NULL) {
76 return;
77 }
78 if (fstab->head != NULL) {
79 item->next = fstab->head->next;
80 fstab->head->next = item;
81 } else {
82 fstab->head = item;
83 }
84 }
85
ReleaseFstabItem(FstabItem * item)86 void ReleaseFstabItem(FstabItem *item)
87 {
88 if (item != NULL) {
89 if (item->deviceName != NULL) {
90 free(item->deviceName);
91 item->deviceName = NULL;
92 }
93
94 if (item->mountPoint != NULL) {
95 free(item->mountPoint);
96 item->mountPoint = NULL;
97 }
98
99 if (item->fsType != NULL) {
100 free(item->fsType);
101 item->fsType = NULL;
102 }
103
104 if (item->mountOptions != NULL) {
105 free(item->mountOptions);
106 item->mountOptions = NULL;
107 }
108
109 free(item);
110 }
111 }
112
ReleaseFstab(Fstab * fstab)113 void ReleaseFstab(Fstab *fstab)
114 {
115 if (fstab != NULL) {
116 FstabItem *item = fstab->head;
117 while (item != NULL) {
118 FstabItem *tmp = item->next;
119 ReleaseFstabItem(item);
120 item = tmp;
121 }
122 free(fstab);
123 fstab = NULL;
124 }
125 }
126
ParseFstabPerLine(char * str,Fstab * fstab,bool procMounts)127 static int ParseFstabPerLine(char *str, Fstab *fstab, bool procMounts)
128 {
129 BEGET_CHECK_RETURN_VALUE(str != NULL && fstab != NULL, -1);
130 const char *separator = " \t";
131 char *rest = NULL;
132 FstabItem *item = NULL;
133 char *p = NULL;
134
135 if ((item = (FstabItem *)calloc(1, sizeof(FstabItem))) == NULL) {
136 errno = ENOMEM;
137 BEGET_LOGE("Allocate memory for FS table item failed, err = %d", errno);
138 return -1;
139 }
140
141 do {
142 if ((p = strtok_r(str, separator, &rest)) == NULL) {
143 BEGET_LOGE("Failed to parse block device.");
144 break;
145 }
146 item->deviceName = strdup(p);
147
148 if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
149 BEGET_LOGE("Failed to parse mount point.");
150 break;
151 }
152 item->mountPoint = strdup(p);
153
154 if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
155 BEGET_LOGE("Failed to parse fs type.");
156 break;
157 }
158 item->fsType = strdup(p);
159
160 if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
161 BEGET_LOGE("Failed to parse mount options.");
162 break;
163 }
164 item->mountOptions = strdup(p);
165
166 if ((p = strtok_r(NULL, separator, &rest)) == NULL) {
167 BEGET_LOGE("Failed to parse fs manager flags.");
168 break;
169 }
170 // @fsManagerFlags only for fstab
171 // Ignore it if we read from /proc/mounts
172 if (!procMounts) {
173 item->fsManagerFlags = ConvertFlags(p);
174 } else {
175 item->fsManagerFlags = 0;
176 }
177 AddToFstab(fstab, item);
178 return 0;
179 } while (0);
180
181 ReleaseFstabItem(item);
182 item = NULL;
183 return -1;
184 }
185
ReadFstabFromFile(const char * file,bool procMounts)186 Fstab *ReadFstabFromFile(const char *file, bool procMounts)
187 {
188 char *line = NULL;
189 size_t allocn = 0;
190 ssize_t readn = 0;
191 Fstab *fstab = NULL;
192
193 FILE *fp = NULL;
194 char *realPath = GetRealPath(file);
195 if (realPath != NULL) {
196 fp = fopen(realPath, "r");
197 free(realPath);
198 } else {
199 fp = fopen(file, "r"); // no file system, can not get real path
200 }
201 if (fp == NULL) {
202 BEGET_LOGE("Open %s failed, err = %d", file, errno);
203 return NULL;
204 }
205
206 if ((fstab = (Fstab *)calloc(1, sizeof(Fstab))) == NULL) {
207 BEGET_LOGE("Allocate memory for FS table failed, err = %d", errno);
208 fclose(fp);
209 fp = NULL;
210 return NULL;
211 }
212
213 // Record line number of fstab file
214 size_t ln = 0;
215 while ((readn = getline(&line, &allocn, fp)) != -1) {
216 char *p = NULL;
217 ln++;
218 if (line[readn - 1] == '\n') {
219 line[readn - 1] = '\0';
220 }
221 p = line;
222 while (isspace(*p)) {
223 p++;
224 }
225
226 if (*p == '\0' || *p == '#') {
227 continue;
228 }
229
230 if (ParseFstabPerLine(p, fstab, procMounts) < 0) {
231 if (errno == ENOMEM) {
232 // Ran out of memory, there is no reason to continue.
233 break;
234 }
235 // If one line in fstab file parsed with a failure. just give a warning
236 // and skip it.
237 BEGET_LOGW("Cannot parse file \" %s \" at line %zu. skip it", file, ln);
238 continue;
239 }
240 }
241 if (line != NULL) {
242 free(line);
243 }
244 (void)fclose(fp);
245 fp = NULL;
246 return fstab;
247 }
248
FindFstabItemForMountPoint(Fstab fstab,const char * mp)249 FstabItem *FindFstabItemForMountPoint(Fstab fstab, const char *mp)
250 {
251 FstabItem *item = NULL;
252 if (mp != NULL) {
253 for (item = fstab.head; item != NULL; item = item->next) {
254 if ((item->mountPoint != NULL) && (strcmp(item->mountPoint, mp) == 0)) {
255 break;
256 }
257 }
258 }
259 return item;
260 }
261
FindFstabItemForPath(Fstab fstab,const char * path)262 FstabItem *FindFstabItemForPath(Fstab fstab, const char *path)
263 {
264 FstabItem *item = NULL;
265
266 if (path == NULL || *path == '\0') {
267 return NULL;
268 }
269
270 char tmp[PATH_MAX] = {0};
271 char *dir = NULL;
272 if (strncpy_s(tmp, PATH_MAX - 1, path, strlen(path)) != EOK) {
273 BEGET_LOGE("Failed to copy path.");
274 return NULL;
275 }
276
277 dir = tmp;
278 while (true) {
279 item = FindFstabItemForMountPoint(fstab, dir);
280 if (item != NULL) {
281 break;
282 }
283 dir = dirname(dir);
284 // Reverse walk through path and met "/", just quit.
285 if (dir == NULL || strcmp(dir, "/") == 0) {
286 break;
287 }
288 }
289 return item;
290 }
291
GetFstabFile(char * fileName,int size)292 static char *GetFstabFile(char *fileName, int size)
293 {
294 if (InUpdaterMode() == 1) {
295 if (strncpy_s(fileName, size, "/etc/fstab.updater", strlen("/etc/fstab.updater")) != 0) {
296 BEGET_LOGE("Failed strncpy_s err=%d", errno);
297 return NULL;
298 }
299 } else {
300 char hardware[MAX_BUFFER_LEN] = {0};
301 char *buffer = ReadFileData("/proc/cmdline");
302 if (buffer == NULL) {
303 BEGET_LOGE("Failed read \"/proc/cmdline\"");
304 return NULL;
305 }
306 int ret = GetProcCmdlineValue("hardware", buffer, hardware, MAX_BUFFER_LEN);
307 free(buffer);
308 if (ret != 0) {
309 BEGET_LOGE("Failed get hardware from cmdline");
310 return NULL;
311 }
312 if (snprintf_s(fileName, size, size - 1, "/vendor/etc/fstab.%s", hardware) == -1) {
313 BEGET_LOGE("Fail snprintf_s err=%d", errno);
314 return NULL;
315 }
316 }
317 BEGET_LOGI("file is %s", fileName);
318 return fileName;
319 }
320
GetBlockDeviceByMountPoint(const char * mountPoint,const Fstab * fstab,char * deviceName,int nameLen)321 int GetBlockDeviceByMountPoint(const char *mountPoint, const Fstab *fstab, char *deviceName, int nameLen)
322 {
323 if (fstab == NULL || mountPoint == NULL || *mountPoint == '\0' || deviceName == NULL) {
324 return -1;
325 }
326 FstabItem *item = FindFstabItemForMountPoint(*fstab, mountPoint);
327 if (item == NULL) {
328 BEGET_LOGE("Failed get fstab item from point \" %s \"", mountPoint);
329 return -1;
330 }
331 if (strncpy_s(deviceName, nameLen, item->deviceName, strlen(item->deviceName)) != 0) {
332 BEGET_LOGE("Failed strncpy_s err=%d", errno);
333 return -1;
334 }
335 return 0;
336 }
337
338 static const struct MountFlags mountFlags[] = {
339 { "noatime", MS_NOATIME },
340 { "noexec", MS_NOEXEC },
341 { "nosuid", MS_NOSUID },
342 { "nodev", MS_NODEV },
343 { "nodiratime", MS_NODIRATIME },
344 { "ro", MS_RDONLY },
345 { "rw", 0 },
346 { "sync", MS_SYNCHRONOUS },
347 { "remount", MS_REMOUNT },
348 { "bind", MS_BIND },
349 { "rec", MS_REC },
350 { "unbindable", MS_UNBINDABLE },
351 { "private", MS_PRIVATE },
352 { "slave", MS_SLAVE },
353 { "shared", MS_SHARED },
354 { "defaults", 0 },
355 };
356
IsDefaultMountFlags(const char * str)357 static bool IsDefaultMountFlags(const char *str)
358 {
359 bool isDefault = false;
360
361 if (str != NULL) {
362 for (size_t i = 0; i < ARRAY_LENGTH(mountFlags); i++) {
363 if (strcmp(str, mountFlags[i].name) == 0) {
364 isDefault = true;
365 }
366 }
367 }
368 return isDefault;
369 }
370
ParseDefaultMountFlag(const char * str)371 static unsigned long ParseDefaultMountFlag(const char *str)
372 {
373 unsigned long flags = 0;
374
375 if (str != NULL) {
376 for (size_t i = 0; i < ARRAY_LENGTH(mountFlags); i++) {
377 if (strcmp(str, mountFlags[i].name) == 0) {
378 flags = mountFlags[i].flags;
379 break;
380 }
381 }
382 }
383 return flags;
384 }
385
GetMountFlags(char * mountFlag,char * fsSpecificData,size_t fsSpecificDataSize)386 unsigned long GetMountFlags(char *mountFlag, char *fsSpecificData, size_t fsSpecificDataSize)
387 {
388 unsigned long flags = 0;
389 BEGET_CHECK_RETURN_VALUE(mountFlag != NULL && fsSpecificData != NULL, 0);
390 int flagCount = 0;
391 // Why max count of mount flags is 15?
392 // There are lots for mount flags defined in sys/mount.h
393 // But we only support to parse 15 in @ParseDefaultMountFlags() function
394 // So set default mount flag number to 15.
395 // If the item configured in fstab contains flag over than 15,
396 // @SplitStringExt can handle it and parse them all. but the parse function will drop it.
397 const int maxCount = 15;
398 char **flagsVector = SplitStringExt(mountFlag, ",", &flagCount, maxCount);
399
400 if (flagsVector == NULL || flagCount == 0) {
401 // No flags or something wrong in SplitStringExt,just return.
402 return 0;
403 }
404
405 for (int i = 0; i < flagCount; i++) {
406 char *p = flagsVector[i];
407 if (IsDefaultMountFlags(p)) {
408 flags |= ParseDefaultMountFlag(p);
409 } else {
410 if (strncat_s(fsSpecificData, fsSpecificDataSize - 1, p, strlen(p)) != EOK) {
411 BEGET_LOGW("Failed to append mount flag \" %s \", ignore it.", p);
412 continue;
413 }
414 if (i == flagCount - 1) { // last flags, do not need to append ','
415 break;
416 }
417 // Combined each mount flag with ','
418 if (strncat_s(fsSpecificData, fsSpecificDataSize - 1, ",", 1) != EOK) {
419 BEGET_LOGW("Failed to append comma.");
420 break; // If cannot add ',' to the end of flags, there is not reason to continue.
421 }
422 }
423 }
424
425 FreeStringVector(flagsVector, flagCount);
426 return flags;
427 }
428
GetBlockDevicePath(const char * partName,char * path,int size)429 int GetBlockDevicePath(const char *partName, char *path, int size)
430 {
431 char *fstabFile = GetFstabFile(path, size);
432 if (fstabFile == NULL) {
433 return -1;
434 }
435 Fstab *fstab = ReadFstabFromFile(fstabFile, false);
436 if (fstab == NULL) {
437 return -1;
438 }
439 int ret = GetBlockDeviceByMountPoint(partName, fstab, path, size);
440 ReleaseFstab(fstab);
441 return ret;
442 }
443
444 #ifdef __cplusplus
445 #if __cplusplus
446 }
447 #endif
448 #endif
449