1 // Copyright 2014 The Android Open Source Project
2 //
3 // This software is licensed under the terms of the GNU General Public
4 // License version 2, as published by the Free Software Foundation, and
5 // may be copied, distributed, and modified under those terms.
6 //
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License for more details.
11
12 #include "android/filesystems/fstab_parser.h"
13
14 #include <ctype.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 namespace {
19
skipWhitespace(const char * p,const char * end)20 const char* skipWhitespace(const char* p, const char* end) {
21 while (p < end && isspace(*p)) {
22 p++;
23 }
24 return p;
25 }
26
skipNonWhitespace(const char * p,const char * end)27 const char* skipNonWhitespace(const char* p, const char* end) {
28 while (p < end && !isspace(*p)) {
29 p++;
30 }
31 return p;
32 }
33
skipExpectedToken(const char * p,const char * end)34 const char* skipExpectedToken(const char* p, const char* end) {
35 p = skipWhitespace(p, end);
36 if (p == end) {
37 return NULL;
38 }
39 return skipNonWhitespace(p, end);
40 }
41
getTokenLen(const char * p,const char * end)42 size_t getTokenLen(const char* p, const char* end) {
43 const char* q = skipNonWhitespace(p, end);
44 return (size_t)(q - p);
45 }
46
47 } // namespace
48
android_parseFstabPartitionFormat(const char * fstabData,size_t fstabSize,const char * partitionName,char ** out)49 bool android_parseFstabPartitionFormat(const char* fstabData,
50 size_t fstabSize,
51 const char* partitionName,
52 char** out) {
53 const char* p = fstabData;
54 const char* end = p + fstabSize;
55
56 size_t partitionNameLen = strlen(partitionName);
57
58 while (p < end) {
59 // Find end of current line, and start of next one.
60 const char* line = p;
61 const char* line_end = ::strchr(p, '\n');
62 if (!line_end) {
63 line_end = end;
64 p = end;
65 } else {
66 p = line_end + 1;
67 }
68
69 // Skip empty or comment lines.
70 line = skipWhitespace(line, line_end);
71 if (line == line_end || line[0] == '#') {
72 continue;
73 }
74
75 // expected format: <device><ws><partition><ws><format><ws><options>
76
77 // skip over device name.
78 line = skipExpectedToken(line, line_end);
79 if (!line) {
80 continue;
81 }
82
83 line = skipWhitespace(line, line_end);
84 size_t tokenLen = getTokenLen(line, line_end);
85 if (tokenLen != partitionNameLen ||
86 memcmp(line, partitionName, tokenLen) != 0) {
87 // Not the right partition.
88 continue;
89 }
90
91 line = skipWhitespace(line + tokenLen, line_end);
92 size_t formatLen = getTokenLen(line, line_end);
93 if (formatLen == 0) {
94 // Malformed data.
95 return false;
96 }
97
98 *out = static_cast<char*>(malloc(formatLen + 1U));
99 memcpy(*out, line, formatLen);
100 (*out)[formatLen] = '\0';
101 return true;
102 }
103 return false;
104 }
105