1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2020 Red Hat, Inc.  All rights reserved.
4 * Author: Zorro Lang <zlang@redhat.com>
5 *
6 * Basic fsmount() test.
7 */
8
9#include "tst_test.h"
10#include "lapi/fsmount.h"
11
12#define MNTPOINT	"mntpoint"
13
14#define TCASE_ENTRY(_flags, _attrs)	{.name = "Flag " #_flags ", Attr " #_attrs, .flags = _flags, .attrs = _attrs}
15
16static struct tcase {
17	char *name;
18	unsigned int flags;
19	unsigned int attrs;
20} tcases[] = {
21	TCASE_ENTRY(0, MOUNT_ATTR_RDONLY),
22	TCASE_ENTRY(0, MOUNT_ATTR_NOSUID),
23	TCASE_ENTRY(0, MOUNT_ATTR_NODEV),
24	TCASE_ENTRY(0, MOUNT_ATTR_NOEXEC),
25	TCASE_ENTRY(0, MOUNT_ATTR_RELATIME),
26	TCASE_ENTRY(0, MOUNT_ATTR_NOATIME),
27	TCASE_ENTRY(0, MOUNT_ATTR_STRICTATIME),
28	TCASE_ENTRY(0, MOUNT_ATTR_NODIRATIME),
29	TCASE_ENTRY(FSMOUNT_CLOEXEC, MOUNT_ATTR_RDONLY),
30	TCASE_ENTRY(FSMOUNT_CLOEXEC, MOUNT_ATTR_NOSUID),
31	TCASE_ENTRY(FSMOUNT_CLOEXEC, MOUNT_ATTR_NODEV),
32	TCASE_ENTRY(FSMOUNT_CLOEXEC, MOUNT_ATTR_NOEXEC),
33	TCASE_ENTRY(FSMOUNT_CLOEXEC, MOUNT_ATTR_RELATIME),
34	TCASE_ENTRY(FSMOUNT_CLOEXEC, MOUNT_ATTR_NOATIME),
35	TCASE_ENTRY(FSMOUNT_CLOEXEC, MOUNT_ATTR_STRICTATIME),
36	TCASE_ENTRY(FSMOUNT_CLOEXEC, MOUNT_ATTR_NODIRATIME),
37};
38
39static void run(unsigned int n)
40{
41	struct tcase *tc = &tcases[n];
42	int sfd, mfd;
43
44	TEST(sfd = fsopen(tst_device->fs_type, FSOPEN_CLOEXEC));
45	if (sfd == -1) {
46		tst_res(TFAIL | TTERRNO, "fsopen() on %s failed",
47			tst_device->fs_type);
48		return;
49	}
50
51	TEST(fsconfig(sfd, FSCONFIG_SET_STRING, "source", tst_device->dev, 0));
52	if (TST_RET == -1) {
53		SAFE_CLOSE(sfd);
54		tst_res(TFAIL | TTERRNO,
55			"fsconfig(FSCONFIG_SET_STRING) failed to set source to %s", tst_device->dev);
56		return;
57	}
58
59	TEST(fsconfig(sfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0));
60	if (TST_RET == -1) {
61		SAFE_CLOSE(sfd);
62		tst_res(TFAIL | TTERRNO, "fsconfig(FSCONFIG_CMD_CREATE) failed");
63		return;
64	}
65
66	TEST(mfd = fsmount(sfd, tc->flags, tc->attrs));
67	SAFE_CLOSE(sfd);
68
69	if (mfd == -1) {
70		tst_res(TFAIL | TTERRNO,
71			"fsmount() failed to create a mount object");
72		return;
73	}
74
75	TEST(move_mount(mfd, "", AT_FDCWD, MNTPOINT, MOVE_MOUNT_F_EMPTY_PATH));
76	SAFE_CLOSE(mfd);
77
78	if (TST_RET == -1) {
79		tst_res(TFAIL | TTERRNO,
80			"move_mount() failed to attach to the mount point");
81		return;
82	}
83
84	if (tst_is_mounted_at_tmpdir(MNTPOINT)) {
85		SAFE_UMOUNT(MNTPOINT);
86		tst_res(TPASS, "%s: fsmount() passed", tc->name);
87	}
88}
89
90static struct tst_test test = {
91	.tcnt = ARRAY_SIZE(tcases),
92	.test = run,
93	.setup = fsopen_supported_by_kernel,
94	.needs_root = 1,
95	.mntpoint = MNTPOINT,
96	.format_device = 1,
97	.all_filesystems = 1,
98	.skip_filesystems = (const char *const []){"fuse", NULL},
99};
100