xref: /freebsd/tests/sys/fs/fusefs/mount.cc (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1a6fac00cSAlan Somers /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3a6fac00cSAlan Somers  *
4a6fac00cSAlan Somers  * Copyright (c) 2019 The FreeBSD Foundation
5a6fac00cSAlan Somers  *
6a6fac00cSAlan Somers  * This software was developed by BFF Storage Systems, LLC under sponsorship
7a6fac00cSAlan Somers  * from the FreeBSD Foundation.
8a6fac00cSAlan Somers  *
9a6fac00cSAlan Somers  * Redistribution and use in source and binary forms, with or without
10a6fac00cSAlan Somers  * modification, are permitted provided that the following conditions
11a6fac00cSAlan Somers  * are met:
12a6fac00cSAlan Somers  * 1. Redistributions of source code must retain the above copyright
13a6fac00cSAlan Somers  *    notice, this list of conditions and the following disclaimer.
14a6fac00cSAlan Somers  * 2. Redistributions in binary form must reproduce the above copyright
15a6fac00cSAlan Somers  *    notice, this list of conditions and the following disclaimer in the
16a6fac00cSAlan Somers  *    documentation and/or other materials provided with the distribution.
17a6fac00cSAlan Somers  *
18a6fac00cSAlan Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19a6fac00cSAlan Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20a6fac00cSAlan Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21a6fac00cSAlan Somers  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22a6fac00cSAlan Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23a6fac00cSAlan Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24a6fac00cSAlan Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25a6fac00cSAlan Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26a6fac00cSAlan Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27a6fac00cSAlan Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28a6fac00cSAlan Somers  * SUCH DAMAGE.
29a6fac00cSAlan Somers  */
30a6fac00cSAlan Somers 
31a6fac00cSAlan Somers extern "C" {
32a6fac00cSAlan Somers #include <sys/param.h>
33a6fac00cSAlan Somers #include <sys/mount.h>
34a6fac00cSAlan Somers #include <sys/uio.h>
35a6fac00cSAlan Somers 
36a6fac00cSAlan Somers #include "mntopts.h"	// for build_iovec
37a6fac00cSAlan Somers }
38a6fac00cSAlan Somers 
39a6fac00cSAlan Somers #include "mockfs.hh"
40a6fac00cSAlan Somers #include "utils.hh"
41a6fac00cSAlan Somers 
42a6fac00cSAlan Somers using namespace testing;
43a6fac00cSAlan Somers 
44616eaa66SAlan Somers class Mount: public FuseTest {
45616eaa66SAlan Somers public:
expect_statfs()46616eaa66SAlan Somers void expect_statfs() {
47616eaa66SAlan Somers 	EXPECT_CALL(*m_mock, process(
48616eaa66SAlan Somers 		ResultOf([](auto in) {
49616eaa66SAlan Somers 			return (in.header.opcode == FUSE_STATFS);
50616eaa66SAlan Somers 		}, Eq(true)),
51616eaa66SAlan Somers 		_)
52616eaa66SAlan Somers 	).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
53616eaa66SAlan Somers 		SET_OUT_HEADER_LEN(out, statfs);
54616eaa66SAlan Somers 	})));
55616eaa66SAlan Somers }
56616eaa66SAlan Somers };
572f636248SAlan Somers 
582f636248SAlan Somers class Fsname: public Mount {
SetUp()592f636248SAlan Somers 	void SetUp() {
602f636248SAlan Somers 		m_fsname = "http://something";
612f636248SAlan Somers 		Mount::SetUp();
622f636248SAlan Somers 	}
632f636248SAlan Somers };
642f636248SAlan Somers 
65616eaa66SAlan Somers class Subtype: public Mount {
SetUp()66616eaa66SAlan Somers 	void SetUp() {
67616eaa66SAlan Somers 		m_subtype = "myfs";
68616eaa66SAlan Somers 		Mount::SetUp();
69616eaa66SAlan Somers 	}
70616eaa66SAlan Somers };
71616eaa66SAlan Somers 
72616eaa66SAlan Somers class UpdateOk: public Mount, public WithParamInterface<const char*> {};
73616eaa66SAlan Somers class UpdateErr: public Mount, public WithParamInterface<const char*> {};
74a6fac00cSAlan Somers 
mntflag_from_string(const char * s)75a6fac00cSAlan Somers int mntflag_from_string(const char *s)
76a6fac00cSAlan Somers {
77a6fac00cSAlan Somers 	if (0 == strcmp("MNT_RDONLY", s))
78a6fac00cSAlan Somers 		return MNT_RDONLY;
79a6fac00cSAlan Somers 	else if (0 == strcmp("MNT_NOEXEC", s))
80a6fac00cSAlan Somers 		return MNT_NOEXEC;
81a6fac00cSAlan Somers 	else if (0 == strcmp("MNT_NOSUID", s))
82a6fac00cSAlan Somers 		return MNT_NOSUID;
83a6fac00cSAlan Somers 	else if (0 == strcmp("MNT_NOATIME", s))
84a6fac00cSAlan Somers 		return MNT_NOATIME;
85a6fac00cSAlan Somers 	else if (0 == strcmp("MNT_SUIDDIR", s))
86a6fac00cSAlan Somers 		return MNT_SUIDDIR;
87a6fac00cSAlan Somers 	else if (0 == strcmp("MNT_USER", s))
88a6fac00cSAlan Somers 		return MNT_USER;
89a6fac00cSAlan Somers 	else
90a6fac00cSAlan Somers 		return 0;
91a6fac00cSAlan Somers }
92a6fac00cSAlan Somers 
TEST_F(Fsname,fsname)932f636248SAlan Somers TEST_F(Fsname, fsname)
942f636248SAlan Somers {
952f636248SAlan Somers 	struct statfs statbuf;
962f636248SAlan Somers 
972f636248SAlan Somers 	expect_statfs();
982f636248SAlan Somers 
992f636248SAlan Somers 	ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno);
1002f636248SAlan Somers 	ASSERT_STREQ("http://something", statbuf.f_mntfromname);
1012f636248SAlan Somers }
1022f636248SAlan Somers 
TEST_F(Subtype,subtype)103616eaa66SAlan Somers TEST_F(Subtype, subtype)
104616eaa66SAlan Somers {
105616eaa66SAlan Somers 	struct statfs statbuf;
106616eaa66SAlan Somers 
107616eaa66SAlan Somers 	expect_statfs();
108616eaa66SAlan Somers 
109616eaa66SAlan Somers 	ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno);
1102f636248SAlan Somers 	ASSERT_STREQ("fusefs.myfs", statbuf.f_fstypename);
111616eaa66SAlan Somers }
112616eaa66SAlan Somers 
113a6fac00cSAlan Somers /* Some mount options can be changed by mount -u */
TEST_P(UpdateOk,update)114a6fac00cSAlan Somers TEST_P(UpdateOk, update)
115a6fac00cSAlan Somers {
116a6fac00cSAlan Somers 	struct statfs statbuf;
117a6fac00cSAlan Somers 	struct iovec *iov = NULL;
118a6fac00cSAlan Somers 	int iovlen = 0;
119a6fac00cSAlan Somers 	int flag;
120a6fac00cSAlan Somers 	int newflags = MNT_UPDATE | MNT_SYNCHRONOUS;
121a6fac00cSAlan Somers 
122a6fac00cSAlan Somers 	flag = mntflag_from_string(GetParam());
123a6fac00cSAlan Somers 	if (flag == MNT_NOSUID && 0 != geteuid())
124a6fac00cSAlan Somers 		GTEST_SKIP() << "Only root may clear MNT_NOSUID";
125a6fac00cSAlan Somers 	if (flag == MNT_SUIDDIR && 0 != geteuid())
126a6fac00cSAlan Somers 		GTEST_SKIP() << "Only root may set MNT_SUIDDIR";
127a6fac00cSAlan Somers 
128a6fac00cSAlan Somers 	EXPECT_CALL(*m_mock, process(
129a6fac00cSAlan Somers 		ResultOf([](auto in) {
13029edc611SAlan Somers 			return (in.header.opcode == FUSE_STATFS);
131a6fac00cSAlan Somers 		}, Eq(true)),
132a6fac00cSAlan Somers 		_)
13329edc611SAlan Somers 	).WillRepeatedly(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
134a6fac00cSAlan Somers 		/*
135a6fac00cSAlan Somers 		 * All of the fields except f_flags are don't care, and f_flags is set by
136a6fac00cSAlan Somers 		 * the VFS
137a6fac00cSAlan Somers 		 */
138a6fac00cSAlan Somers 		SET_OUT_HEADER_LEN(out, statfs);
139a6fac00cSAlan Somers 	})));
140a6fac00cSAlan Somers 
141a6fac00cSAlan Somers 	ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno);
142a6fac00cSAlan Somers 	newflags = (statbuf.f_flags | MNT_UPDATE) ^ flag;
143a6fac00cSAlan Somers 
144a6fac00cSAlan Somers 	build_iovec(&iov, &iovlen, "fstype", (void*)statbuf.f_fstypename, -1);
145a6fac00cSAlan Somers 	build_iovec(&iov, &iovlen, "fspath", (void*)statbuf.f_mntonname, -1);
146a6fac00cSAlan Somers 	build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1);
147a6fac00cSAlan Somers 	ASSERT_EQ(0, nmount(iov, iovlen, newflags)) << strerror(errno);
148a6fac00cSAlan Somers 
149a6fac00cSAlan Somers 	ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno);
150a6fac00cSAlan Somers 	EXPECT_FALSE((newflags ^ statbuf.f_flags) & flag);
151a6fac00cSAlan Somers }
152a6fac00cSAlan Somers 
153a6fac00cSAlan Somers /* Some mount options cannnot be changed by mount -u */
TEST_P(UpdateErr,update)154a6fac00cSAlan Somers TEST_P(UpdateErr, update)
155a6fac00cSAlan Somers {
156a6fac00cSAlan Somers 	struct statfs statbuf;
157a6fac00cSAlan Somers 	struct iovec *iov = NULL;
158a6fac00cSAlan Somers 	int iovlen = 0;
159a6fac00cSAlan Somers 	int flag;
160a6fac00cSAlan Somers 	int newflags = MNT_UPDATE | MNT_SYNCHRONOUS;
161a6fac00cSAlan Somers 
162a6fac00cSAlan Somers 	flag = mntflag_from_string(GetParam());
163a6fac00cSAlan Somers 	EXPECT_CALL(*m_mock, process(
164a6fac00cSAlan Somers 		ResultOf([](auto in) {
16529edc611SAlan Somers 			return (in.header.opcode == FUSE_STATFS);
166a6fac00cSAlan Somers 		}, Eq(true)),
167a6fac00cSAlan Somers 		_)
16829edc611SAlan Somers 	).WillRepeatedly(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
169a6fac00cSAlan Somers 		/*
170a6fac00cSAlan Somers 		 * All of the fields except f_flags are don't care, and f_flags is set by
171a6fac00cSAlan Somers 		 * the VFS
172a6fac00cSAlan Somers 		 */
173a6fac00cSAlan Somers 		SET_OUT_HEADER_LEN(out, statfs);
174a6fac00cSAlan Somers 	})));
175a6fac00cSAlan Somers 
176a6fac00cSAlan Somers 	ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno);
177a6fac00cSAlan Somers 	newflags = (statbuf.f_flags | MNT_UPDATE) ^ flag;
178a6fac00cSAlan Somers 
179a6fac00cSAlan Somers 	build_iovec(&iov, &iovlen, "fstype", (void*)statbuf.f_fstypename, -1);
180a6fac00cSAlan Somers 	build_iovec(&iov, &iovlen, "fspath", (void*)statbuf.f_mntonname, -1);
181a6fac00cSAlan Somers 	build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1);
182a6fac00cSAlan Somers 	/*
183a6fac00cSAlan Somers 	 * Don't check nmount's return value, because vfs_domount may "fix" the
184a6fac00cSAlan Somers 	 * options for us.  The important thing is to check the final value of
185a6fac00cSAlan Somers 	 * statbuf.f_flags below.
186a6fac00cSAlan Somers 	 */
187a6fac00cSAlan Somers 	(void)nmount(iov, iovlen, newflags);
188a6fac00cSAlan Somers 
189a6fac00cSAlan Somers 	ASSERT_EQ(0, statfs("mountpoint", &statbuf)) << strerror(errno);
190a6fac00cSAlan Somers 	EXPECT_TRUE((newflags ^ statbuf.f_flags) & flag);
191a6fac00cSAlan Somers }
192a6fac00cSAlan Somers 
193*811e0a31SEnji Cooper INSTANTIATE_TEST_SUITE_P(Mount, UpdateOk,
194a6fac00cSAlan Somers 		::testing::Values("MNT_RDONLY", "MNT_NOEXEC", "MNT_NOSUID", "MNT_NOATIME",
195a6fac00cSAlan Somers 		"MNT_SUIDDIR")
196a6fac00cSAlan Somers );
197a6fac00cSAlan Somers 
198*811e0a31SEnji Cooper INSTANTIATE_TEST_SUITE_P(Mount, UpdateErr,
199*811e0a31SEnji Cooper 		::testing::Values( "MNT_USER")
200a6fac00cSAlan Somers );
201