Merge changes from topic "revert-1890098-KOOTTLPTTT"
* changes:
Revert "Replace strtok_r() with C++-style android::base::Tokenize()"
Revert "Add ParseFstabFromString(), remove ReadFstabFromFp()"
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 809aa61..9b51529 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -530,37 +530,67 @@
} // namespace
-bool ParseFstabFromString(const std::string& fstab_str, bool proc_mounts, Fstab* fstab_out) {
- const int expected_fields = proc_mounts ? 4 : 5;
-
+bool ReadFstabFromFp(FILE* fstab_file, bool proc_mounts, Fstab* fstab_out) {
+ ssize_t len;
+ size_t alloc_len = 0;
+ char *line = NULL;
+ const char *delim = " \t";
+ char *save_ptr, *p;
Fstab fstab;
- for (const auto& line : android::base::Split(fstab_str, "\n")) {
- auto fields = android::base::Tokenize(line, " \t");
+ while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
+ /* if the last character is a newline, shorten the string by 1 byte */
+ if (line[len - 1] == '\n') {
+ line[len - 1] = '\0';
+ }
- // Ignore empty lines and comments.
- if (fields.empty() || android::base::StartsWith(fields.front(), '#')) {
+ /* Skip any leading whitespace */
+ p = line;
+ while (isspace(*p)) {
+ p++;
+ }
+ /* ignore comments or empty lines */
+ if (*p == '#' || *p == '\0')
continue;
- }
-
- if (fields.size() < expected_fields) {
- LERROR << "Error parsing fstab: expected " << expected_fields << " fields, got "
- << fields.size();
- return false;
- }
FstabEntry entry;
- auto it = fields.begin();
- entry.blk_device = std::move(*it++);
- entry.mount_point = std::move(*it++);
- entry.fs_type = std::move(*it++);
- ParseMountFlags(std::move(*it++), &entry);
+ if (!(p = strtok_r(line, delim, &save_ptr))) {
+ LERROR << "Error parsing mount source";
+ goto err;
+ }
+ entry.blk_device = p;
+
+ if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+ LERROR << "Error parsing mount_point";
+ goto err;
+ }
+ entry.mount_point = p;
+
+ if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+ LERROR << "Error parsing fs_type";
+ goto err;
+ }
+ entry.fs_type = p;
+
+ if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+ LERROR << "Error parsing mount_flags";
+ goto err;
+ }
+
+ ParseMountFlags(p, &entry);
// For /proc/mounts, ignore everything after mnt_freq and mnt_passno
- if (!proc_mounts && !ParseFsMgrFlags(std::move(*it++), &entry)) {
+ if (proc_mounts) {
+ p += strlen(p);
+ } else if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+ LERROR << "Error parsing fs_mgr_options";
+ goto err;
+ }
+
+ if (!ParseFsMgrFlags(p, &entry)) {
LERROR << "Error parsing fs_mgr_flags";
- return false;
+ goto err;
}
if (entry.fs_mgr_flags.logical) {
@@ -572,17 +602,21 @@
if (fstab.empty()) {
LERROR << "No entries found in fstab";
- return false;
+ goto err;
}
/* If an A/B partition, modify block device to be the real block device */
if (!fs_mgr_update_for_slotselect(&fstab)) {
LERROR << "Error updating for slotselect";
- return false;
+ goto err;
}
-
+ free(line);
*fstab_out = std::move(fstab);
return true;
+
+err:
+ free(line);
+ return false;
}
void TransformFstabForDsu(Fstab* fstab, const std::string& dsu_slot,
@@ -681,18 +715,16 @@
}
bool ReadFstabFromFile(const std::string& path, Fstab* fstab_out) {
- const bool is_proc_mounts = (path == "/proc/mounts");
- // /proc/mounts could be a symlink to /proc/self/mounts.
- const bool follow_symlinks = is_proc_mounts;
-
- std::string fstab_str;
- if (!android::base::ReadFileToString(path, &fstab_str, follow_symlinks)) {
- PERROR << __FUNCTION__ << "(): failed to read file: '" << path << "'";
+ auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
+ if (!fstab_file) {
+ PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
return false;
}
+ bool is_proc_mounts = path == "/proc/mounts";
+
Fstab fstab;
- if (!ParseFstabFromString(fstab_str, is_proc_mounts, &fstab)) {
+ if (!ReadFstabFromFp(fstab_file.get(), is_proc_mounts, &fstab)) {
LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'";
return false;
}
@@ -739,7 +771,15 @@
return false;
}
- if (!ParseFstabFromString(fstab_buf, /* proc_mounts = */ false, fstab)) {
+ std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
+ fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
+ fstab_buf.length(), "r"), fclose);
+ if (!fstab_file) {
+ if (verbose) PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
+ return false;
+ }
+
+ if (!ReadFstabFromFp(fstab_file.get(), false, fstab)) {
if (verbose) {
LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
<< fstab_buf;
diff --git a/fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp b/fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp
index 6a8a191..1fddbf8 100644
--- a/fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp
+++ b/fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp
@@ -19,8 +19,12 @@
#include <fstab/fstab.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- std::string make_fstab_str(reinterpret_cast<const char*>(data), size);
+ std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
+ fmemopen(static_cast<void*>(const_cast<uint8_t*>(data)), size, "r"), fclose);
+ if (fstab_file == nullptr) {
+ return 0;
+ }
android::fs_mgr::Fstab fstab;
- android::fs_mgr::ParseFstabFromString(make_fstab_str, /* proc_mounts = */ false, &fstab);
+ android::fs_mgr::ReadFstabFromFp(fstab_file.get(), /* proc_mounts= */ false, &fstab);
return 0;
}
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 054300e..d9c326d 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -94,8 +94,8 @@
// Unless explicitly requested, a lookup on mount point should always return the 1st one.
using Fstab = std::vector<FstabEntry>;
-// Exported for testability. Regular users should use ReadFstabFromFile().
-bool ParseFstabFromString(const std::string& fstab_str, bool proc_mounts, Fstab* fstab_out);
+// Exported for testability. Regular users should use ReadFstabFromfile().
+bool ReadFstabFromFp(FILE* fstab_file, bool proc_mounts, Fstab* fstab_out);
bool ReadFstabFromFile(const std::string& path, Fstab* fstab);
bool ReadFstabFromDt(Fstab* fstab, bool verbose = true);