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
18namespace {
19
20const char* skipWhitespace(const char* p, const char* end) {
21    while (p < end && isspace(*p)) {
22        p++;
23    }
24    return p;
25}
26
27const char* skipNonWhitespace(const char* p, const char* end) {
28    while (p < end && !isspace(*p)) {
29        p++;
30    }
31    return p;
32}
33
34const 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
42size_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
49bool 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