diff options
author | Adin Scannell <ascannell@google.com> | 2021-04-26 16:25:26 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-04-26 16:27:45 -0700 |
commit | 36fdc6c9ef565be34f5ab27affed31eb2430e89a (patch) | |
tree | b7f7abab391f1c9664b5a14ed6f786560d2afc49 /test/util | |
parent | 5b7b7daa425ffc93e98c12cbd37ea7b15a8bcc8d (diff) |
Handle tmpfs with 5 fields in /proc/mounts parsing.
PiperOrigin-RevId: 370565903
Diffstat (limited to 'test/util')
-rw-r--r-- | test/util/BUILD | 12 | ||||
-rw-r--r-- | test/util/mount_util.cc | 32 | ||||
-rw-r--r-- | test/util/mount_util.h | 10 | ||||
-rw-r--r-- | test/util/mount_util_test.cc | 47 |
4 files changed, 90 insertions, 11 deletions
diff --git a/test/util/BUILD b/test/util/BUILD index 6feda0e26..8985b54af 100644 --- a/test/util/BUILD +++ b/test/util/BUILD @@ -149,6 +149,18 @@ cc_library( ], ) +cc_test( + name = "mount_util_test", + size = "small", + srcs = ["mount_util_test.cc"], + deps = [ + ":mount_util", + ":test_main", + ":test_util", + gtest, + ], +) + cc_library( name = "save_util", testonly = 1, diff --git a/test/util/mount_util.cc b/test/util/mount_util.cc index a79ce6420..48640d6a1 100644 --- a/test/util/mount_util.cc +++ b/test/util/mount_util.cc @@ -26,9 +26,14 @@ namespace testing { PosixErrorOr<std::vector<ProcMountsEntry>> ProcSelfMountsEntries() { std::string content; RETURN_IF_ERRNO(GetContents("/proc/self/mounts", &content)); + return ProcSelfMountsEntriesFrom(content); +} +PosixErrorOr<std::vector<ProcMountsEntry>> ProcSelfMountsEntriesFrom( + const std::string& content) { std::vector<ProcMountsEntry> entries; - std::vector<std::string> lines = absl::StrSplit(content, '\n'); + std::vector<std::string> lines = + absl::StrSplit(content, absl::ByChar('\n'), absl::AllowEmpty()); std::cerr << "<contents of /proc/self/mounts>" << std::endl; for (const std::string& line : lines) { std::cerr << line << std::endl; @@ -47,11 +52,11 @@ PosixErrorOr<std::vector<ProcMountsEntry>> ProcSelfMountsEntries() { ProcMountsEntry entry; std::vector<std::string> fields = - absl::StrSplit(line, absl::ByChar(' '), absl::SkipEmpty()); + absl::StrSplit(line, absl::ByChar(' '), absl::AllowEmpty()); if (fields.size() != 6) { - return PosixError(EINVAL, - absl::StrFormat("Not enough tokens, got %d, line: %s", - fields.size(), line)); + return PosixError( + EINVAL, absl::StrFormat("Not enough tokens, got %d, content: <<%s>>", + fields.size(), content)); } entry.spec = fields[0]; @@ -71,9 +76,14 @@ PosixErrorOr<std::vector<ProcMountsEntry>> ProcSelfMountsEntries() { PosixErrorOr<std::vector<ProcMountInfoEntry>> ProcSelfMountInfoEntries() { std::string content; RETURN_IF_ERRNO(GetContents("/proc/self/mountinfo", &content)); + return ProcSelfMountInfoEntriesFrom(content); +} +PosixErrorOr<std::vector<ProcMountInfoEntry>> ProcSelfMountInfoEntriesFrom( + const std::string& content) { std::vector<ProcMountInfoEntry> entries; - std::vector<std::string> lines = absl::StrSplit(content, '\n'); + std::vector<std::string> lines = + absl::StrSplit(content, absl::ByChar('\n'), absl::AllowEmpty()); std::cerr << "<contents of /proc/self/mountinfo>" << std::endl; for (const std::string& line : lines) { std::cerr << line << std::endl; @@ -92,12 +102,12 @@ PosixErrorOr<std::vector<ProcMountInfoEntry>> ProcSelfMountInfoEntries() { ProcMountInfoEntry entry; std::vector<std::string> fields = - absl::StrSplit(line, absl::ByChar(' '), absl::SkipEmpty()); + absl::StrSplit(line, absl::ByChar(' '), absl::AllowEmpty()); if (fields.size() < 10 || fields.size() > 11) { return PosixError( - EINVAL, - absl::StrFormat("Unexpected number of tokens, got %d, line: %s", - fields.size(), line)); + EINVAL, absl::StrFormat( + "Unexpected number of tokens, got %d, content: <<%s>>", + fields.size(), content)); } ASSIGN_OR_RETURN_ERRNO(entry.id, Atoi<uint64_t>(fields[0])); @@ -142,7 +152,7 @@ absl::flat_hash_map<std::string, std::string> ParseMountOptions( std::string mopts) { absl::flat_hash_map<std::string, std::string> entries; const std::vector<std::string> tokens = - absl::StrSplit(mopts, absl::ByChar(','), absl::SkipEmpty()); + absl::StrSplit(mopts, absl::ByChar(','), absl::AllowEmpty()); for (const auto& token : tokens) { std::vector<std::string> kv = absl::StrSplit(token, absl::MaxSplits('=', 1)); diff --git a/test/util/mount_util.h b/test/util/mount_util.h index b75a490fb..3f8a1c0f1 100644 --- a/test/util/mount_util.h +++ b/test/util/mount_util.h @@ -58,6 +58,11 @@ struct ProcMountsEntry { // ProcSelfMountsEntries returns a parsed representation of /proc/self/mounts. PosixErrorOr<std::vector<ProcMountsEntry>> ProcSelfMountsEntries(); +// ProcSelfMountsEntries returns a parsed representation of mounts from the +// provided content. +PosixErrorOr<std::vector<ProcMountsEntry>> ProcSelfMountsEntriesFrom( + const std::string& content); + struct ProcMountInfoEntry { uint64_t id; uint64_t parent_id; @@ -76,6 +81,11 @@ struct ProcMountInfoEntry { // /proc/self/mountinfo. PosixErrorOr<std::vector<ProcMountInfoEntry>> ProcSelfMountInfoEntries(); +// ProcSelfMountInfoEntriesFrom returns a parsed representation of +// mountinfo from the provided content. +PosixErrorOr<std::vector<ProcMountInfoEntry>> ProcSelfMountInfoEntriesFrom( + const std::string&); + // Interprets the input string mopts as a comma separated list of mount // options. A mount option can either be just a value, or a key=value pair. For // example, the string "rw,relatime,fd=7" will be parsed into a map like { "rw": diff --git a/test/util/mount_util_test.cc b/test/util/mount_util_test.cc new file mode 100644 index 000000000..2bcb6cc43 --- /dev/null +++ b/test/util/mount_util_test.cc @@ -0,0 +1,47 @@ +// Copyright 2018 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "test/util/mount_util.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "test/util/test_util.h" + +namespace gvisor { +namespace testing { + +namespace { + +TEST(ParseMounts, Mounts) { + auto entries = ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountsEntriesFrom( + R"proc(sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0 +proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0 + /mnt tmpfs rw,noexec 0 0 +)proc")); + EXPECT_EQ(entries.size(), 3); +} + +TEST(ParseMounts, MountInfo) { + auto entries = ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountInfoEntriesFrom( + R"proc(22 28 0:20 / /sys rw,relatime shared:7 - sysfs sysfs rw +23 28 0:21 / /proc rw,relatime shared:14 - proc proc rw +2007 8844 0:278 / /mnt rw,noexec - tmpfs rw,mode=123,uid=268601820,gid=5000 +)proc")); + EXPECT_EQ(entries.size(), 3); +} + +} // namespace + +} // namespace testing +} // namespace gvisor |