blob: b2d7956d5deee5eb80704b75fb85d36c31cdd33e [file] [log] [blame]
Mike Frysinger38ae98d2012-04-11 12:03:44 -04001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Ben Chane31d2aa2011-06-15 13:52:59 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Alex Deymo4527b9c2014-11-10 19:55:35 -08005#include "cros-disks/system_mounter.h"
6
Ben Chane31d2aa2011-06-15 13:52:59 -07007#include <sys/mount.h>
8
Ben Chan97f99ff2013-02-14 14:59:33 -08009#include <base/files/scoped_temp_dir.h>
Sergei Datsenko3d71d792020-11-17 21:46:22 +110010#include <gmock/gmock.h>
Ben Chane31d2aa2011-06-15 13:52:59 -070011#include <gtest/gtest.h>
12
Ben Chan5ccd9fe2013-11-13 18:28:27 -080013#include "cros-disks/mount_options.h"
Sergei Datsenko85a18332019-04-08 14:25:03 +100014#include "cros-disks/mount_point.h"
Sam McNallyc56ae312018-05-22 13:14:27 +100015#include "cros-disks/platform.h"
Ben Chane31d2aa2011-06-15 13:52:59 -070016
17namespace cros_disks {
18
Sergei Datsenko3d71d792020-11-17 21:46:22 +110019using testing::_;
20using testing::Return;
21
Sergei Datsenkoe8faba52020-10-06 21:45:22 +110022namespace {
Sergei Datsenko3d71d792020-11-17 21:46:22 +110023
24constexpr uint64_t kDefaultMountFlags =
25 MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC | MS_NOSYMFOLLOW;
26
Sergei Datsenkoe8faba52020-10-06 21:45:22 +110027class PlatformForTest : public Platform {
28 public:
29 // Tests are being run on devices that don't support nosymfollow. Strip it.
30 MountErrorType Mount(const std::string& source,
31 const std::string& target,
32 const std::string& filesystem_type,
33 uint64_t flags,
34 const std::string& options) const override {
35 EXPECT_TRUE((flags & MS_NOSYMFOLLOW) == MS_NOSYMFOLLOW);
36 return Platform::Mount(source, target, filesystem_type,
37 flags & ~MS_NOSYMFOLLOW, options);
38 }
39};
Sergei Datsenko3d71d792020-11-17 21:46:22 +110040
41class MockPlatform : public Platform {
42 public:
43 MOCK_METHOD(MountErrorType,
44 Mount,
45 (const std::string& source,
46 const std::string& target,
47 const std::string& filesystem_type,
48 uint64_t flags,
49 const std::string& options),
50 (const, override));
51 MOCK_METHOD(MountErrorType,
52 Unmount,
53 (const std::string& target, int flags),
54 (const, override));
55};
Sergei Datsenkoe8faba52020-10-06 21:45:22 +110056} // namespace
57
Ben Chan33aa2bb2017-03-08 11:21:16 -080058TEST(SystemMounterTest, RunAsRootMount) {
Sergei Datsenkoe8faba52020-10-06 21:45:22 +110059 PlatformForTest platform;
Sergei Datsenko3d71d792020-11-17 21:46:22 +110060 SystemMounter mounter(&platform, "tmpfs", /* read_only= */ false, {});
Sergei Datsenko85a18332019-04-08 14:25:03 +100061
Ben Chan97f99ff2013-02-14 14:59:33 -080062 base::ScopedTempDir temp_dir;
Ben Chane31d2aa2011-06-15 13:52:59 -070063 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
Sergei Datsenko85a18332019-04-08 14:25:03 +100064
François Degros3a796902019-07-12 14:49:58 +100065 MountErrorType error = MOUNT_ERROR_NONE;
Sergei Datsenko85a18332019-04-08 14:25:03 +100066 auto mountpoint = mounter.Mount("/dev/null", temp_dir.GetPath(), {}, &error);
67 EXPECT_TRUE(mountpoint);
François Degros3a796902019-07-12 14:49:58 +100068 EXPECT_EQ(MOUNT_ERROR_NONE, error);
Sergei Datsenko85a18332019-04-08 14:25:03 +100069 error = mountpoint->Unmount();
François Degros3a796902019-07-12 14:49:58 +100070 EXPECT_EQ(MOUNT_ERROR_NONE, error);
Ben Chane31d2aa2011-06-15 13:52:59 -070071}
72
Ben Chan33aa2bb2017-03-08 11:21:16 -080073TEST(SystemMounterTest, RunAsRootMountWithNonexistentSourcePath) {
Sergei Datsenkoe8faba52020-10-06 21:45:22 +110074 PlatformForTest platform;
Sergei Datsenko3d71d792020-11-17 21:46:22 +110075 SystemMounter mounter(&platform, "ext2", /* read_only= */ false, {});
Sergei Datsenko85a18332019-04-08 14:25:03 +100076
Ben Chan97f99ff2013-02-14 14:59:33 -080077 base::ScopedTempDir temp_dir;
Ben Chane31d2aa2011-06-15 13:52:59 -070078 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
Sergei Datsenko85a18332019-04-08 14:25:03 +100079
Ben Chane31d2aa2011-06-15 13:52:59 -070080 // To test mounting a nonexistent source path, use ext2 as the
81 // filesystem type instead of tmpfs since tmpfs does not care
82 // about source path.
François Degros3a796902019-07-12 14:49:58 +100083 MountErrorType error = MOUNT_ERROR_NONE;
Sergei Datsenko85a18332019-04-08 14:25:03 +100084 auto mountpoint =
85 mounter.Mount("/nonexistent", temp_dir.GetPath(), {}, &error);
86 EXPECT_FALSE(mountpoint);
François Degros3a796902019-07-12 14:49:58 +100087 EXPECT_EQ(MOUNT_ERROR_INVALID_PATH, error);
Ben Chane31d2aa2011-06-15 13:52:59 -070088}
89
Ben Chan33aa2bb2017-03-08 11:21:16 -080090TEST(SystemMounterTest, RunAsRootMountWithNonexistentTargetPath) {
Sergei Datsenkoe8faba52020-10-06 21:45:22 +110091 PlatformForTest platform;
Sergei Datsenko3d71d792020-11-17 21:46:22 +110092 SystemMounter mounter(&platform, "tmpfs", /* read_only= */ false, {});
Sergei Datsenko85a18332019-04-08 14:25:03 +100093
François Degros3a796902019-07-12 14:49:58 +100094 MountErrorType error = MOUNT_ERROR_NONE;
Sergei Datsenko85a18332019-04-08 14:25:03 +100095 auto mountpoint =
96 mounter.Mount("/dev/null", base::FilePath("/nonexistent"), {}, &error);
97 EXPECT_FALSE(mountpoint);
François Degros3a796902019-07-12 14:49:58 +100098 EXPECT_EQ(MOUNT_ERROR_INVALID_PATH, error);
Ben Chane31d2aa2011-06-15 13:52:59 -070099}
100
Ben Chan33aa2bb2017-03-08 11:21:16 -0800101TEST(SystemMounterTest, RunAsRootMountWithNonexistentFilesystemType) {
Sergei Datsenkoe8faba52020-10-06 21:45:22 +1100102 PlatformForTest platform;
Sergei Datsenko3d71d792020-11-17 21:46:22 +1100103 SystemMounter mounter(&platform, "nonexistentfs", /* read_only= */ false, {});
Sergei Datsenko85a18332019-04-08 14:25:03 +1000104
Ben Chan97f99ff2013-02-14 14:59:33 -0800105 base::ScopedTempDir temp_dir;
Ben Chane31d2aa2011-06-15 13:52:59 -0700106 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
François Degros3a796902019-07-12 14:49:58 +1000107 MountErrorType error = MOUNT_ERROR_NONE;
Sergei Datsenko85a18332019-04-08 14:25:03 +1000108 auto mountpoint = mounter.Mount("/dev/null", temp_dir.GetPath(), {}, &error);
109 EXPECT_FALSE(mountpoint);
François Degros3a796902019-07-12 14:49:58 +1000110 EXPECT_EQ(MOUNT_ERROR_UNSUPPORTED_FILESYSTEM, error);
Ben Chane31d2aa2011-06-15 13:52:59 -0700111}
112
Sergei Datsenko3d71d792020-11-17 21:46:22 +1100113TEST(SystemMounterTest, MountFilesystem) {
114 MockPlatform platform;
115 SystemMounter mounter(&platform, "fstype", /* read_only= */ false, {});
116
117 EXPECT_CALL(platform, Mount("/dev/block", "/mnt/dir", "fstype", _, _))
118 .WillOnce(Return(MOUNT_ERROR_NONE));
119 MountErrorType error = MOUNT_ERROR_UNKNOWN;
120 auto mountpoint =
121 mounter.Mount("/dev/block", base::FilePath("/mnt/dir"), {}, &error);
122 ASSERT_TRUE(mountpoint);
123 EXPECT_EQ(MOUNT_ERROR_NONE, error);
124
125 EXPECT_CALL(platform, Unmount("/mnt/dir", 0))
126 .WillOnce(Return(MOUNT_ERROR_NONE));
127 mountpoint.reset();
128}
129
130TEST(SystemMounterTest, MountFailed) {
131 MockPlatform platform;
132 SystemMounter mounter(&platform, "fstype", /* read_only= */ false, {});
133
134 EXPECT_CALL(platform, Mount("/dev/block", "/mnt/dir", "fstype", _, _))
135 .WillOnce(Return(MOUNT_ERROR_PATH_NOT_MOUNTED));
136 EXPECT_CALL(platform, Unmount).Times(0);
137
138 MountErrorType error = MOUNT_ERROR_UNKNOWN;
139 auto mountpoint =
140 mounter.Mount("/dev/block", base::FilePath("/mnt/dir"), {}, &error);
141 ASSERT_FALSE(mountpoint);
142 EXPECT_EQ(MOUNT_ERROR_PATH_NOT_MOUNTED, error);
143}
144
145TEST(SystemMounterTest, UnmountFailedNoRetry) {
146 MockPlatform platform;
147 SystemMounter mounter(&platform, "fstype", /* read_only= */ false, {});
148
149 EXPECT_CALL(platform, Mount(_, "/mnt/dir", "fstype", _, _))
150 .WillOnce(Return(MOUNT_ERROR_NONE));
151 MountErrorType error = MOUNT_ERROR_UNKNOWN;
152 auto mountpoint =
153 mounter.Mount("/dev/block", base::FilePath("/mnt/dir"), {}, &error);
154
155 EXPECT_CALL(platform, Unmount("/mnt/dir", 0))
156 .WillOnce(Return(MOUNT_ERROR_INVALID_ARGUMENT))
157 .WillOnce(Return(MOUNT_ERROR_NONE));
158 EXPECT_EQ(MOUNT_ERROR_INVALID_ARGUMENT, mountpoint->Unmount());
159 mountpoint.reset();
160}
161
162TEST(SystemMounterTest, UnmountBusyRetry) {
163 MockPlatform platform;
164 SystemMounter mounter(&platform, "fstype", /* read_only= */ false, {});
165
166 EXPECT_CALL(platform, Mount(_, "/mnt/dir", "fstype", _, _))
167 .WillOnce(Return(MOUNT_ERROR_NONE));
168 MountErrorType error = MOUNT_ERROR_UNKNOWN;
169 auto mountpoint =
170 mounter.Mount("/dev/block", base::FilePath("/mnt/dir"), {}, &error);
171
172 EXPECT_CALL(platform, Unmount("/mnt/dir", 0))
173 .WillOnce(Return(MOUNT_ERROR_PATH_ALREADY_MOUNTED));
Sergei Datsenko0ba12032021-01-07 08:51:14 +1100174 EXPECT_CALL(platform, Unmount("/mnt/dir", MNT_DETACH | MNT_FORCE))
Sergei Datsenko3d71d792020-11-17 21:46:22 +1100175 .WillOnce(Return(MOUNT_ERROR_NONE));
176 EXPECT_EQ(MOUNT_ERROR_NONE, mountpoint->Unmount());
177 mountpoint.reset();
178}
179
180TEST(SystemMounterTest, MountFlags) {
181 MockPlatform platform;
182 SystemMounter mounter(&platform, "fstype", /* read_only= */ false, {});
183
184 EXPECT_CALL(platform, Mount(_, "/mnt/dir", "fstype", kDefaultMountFlags, _))
185 .WillOnce(Return(MOUNT_ERROR_NONE));
186 MountErrorType error = MOUNT_ERROR_UNKNOWN;
187 auto mountpoint =
188 mounter.Mount("/dev/block", base::FilePath("/mnt/dir"), {}, &error);
189}
190
191TEST(SystemMounterTest, ReadOnlyForced) {
192 MockPlatform platform;
193 SystemMounter mounter(&platform, "fstype", /* read_only= */ true, {});
194
195 EXPECT_CALL(platform,
196 Mount(_, "/mnt/dir", "fstype", kDefaultMountFlags | MS_RDONLY, _))
197 .WillOnce(Return(MOUNT_ERROR_NONE));
198 MountErrorType error = MOUNT_ERROR_UNKNOWN;
199 auto mountpoint =
200 mounter.Mount("/dev/block", base::FilePath("/mnt/dir"), {}, &error);
201}
202
203TEST(SystemMounterTest, ReadOnlyRequested) {
204 MockPlatform platform;
205 SystemMounter mounter(&platform, "fstype", /* read_only= */ false, {});
206
207 EXPECT_CALL(platform,
208 Mount(_, "/mnt/dir", "fstype", kDefaultMountFlags | MS_RDONLY, _))
209 .WillOnce(Return(MOUNT_ERROR_NONE));
210 MountErrorType error = MOUNT_ERROR_UNKNOWN;
211 auto mountpoint =
212 mounter.Mount("/dev/block", base::FilePath("/mnt/dir"), {"ro"}, &error);
213}
214
215TEST(SystemMounterTest, MountOptionsPassedButParamsIgnored) {
216 MockPlatform platform;
217 SystemMounter mounter(&platform, "fstype", /* read_only= */ false,
218 {"foo", "bar=baz"});
219
220 EXPECT_CALL(platform, Mount(_, "/mnt/dir", "fstype", _, "foo,bar=baz"))
221 .WillOnce(Return(MOUNT_ERROR_NONE));
222 MountErrorType error = MOUNT_ERROR_UNKNOWN;
223 auto mountpoint = mounter.Mount("/dev/block", base::FilePath("/mnt/dir"),
224 {"abc=def", "xyz"}, &error);
225}
226
Ben Chane31d2aa2011-06-15 13:52:59 -0700227} // namespace cros_disks