162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Author: Aleksa Sarai <cyphar@cyphar.com>
462306a36Sopenharmony_ci * Copyright (C) 2018-2019 SUSE LLC.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#define _GNU_SOURCE
862306a36Sopenharmony_ci#include <fcntl.h>
962306a36Sopenharmony_ci#include <sched.h>
1062306a36Sopenharmony_ci#include <sys/stat.h>
1162306a36Sopenharmony_ci#include <sys/types.h>
1262306a36Sopenharmony_ci#include <sys/mount.h>
1362306a36Sopenharmony_ci#include <stdlib.h>
1462306a36Sopenharmony_ci#include <stdbool.h>
1562306a36Sopenharmony_ci#include <string.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "../kselftest.h"
1862306a36Sopenharmony_ci#include "helpers.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/*
2162306a36Sopenharmony_ci * O_LARGEFILE is set to 0 by glibc.
2262306a36Sopenharmony_ci * XXX: This is wrong on {mips, parisc, powerpc, sparc}.
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci#undef	O_LARGEFILE
2562306a36Sopenharmony_ci#ifdef __aarch64__
2662306a36Sopenharmony_ci#define	O_LARGEFILE 0x20000
2762306a36Sopenharmony_ci#else
2862306a36Sopenharmony_ci#define	O_LARGEFILE 0x8000
2962306a36Sopenharmony_ci#endif
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct open_how_ext {
3262306a36Sopenharmony_ci	struct open_how inner;
3362306a36Sopenharmony_ci	uint32_t extra1;
3462306a36Sopenharmony_ci	char pad1[128];
3562306a36Sopenharmony_ci	uint32_t extra2;
3662306a36Sopenharmony_ci	char pad2[128];
3762306a36Sopenharmony_ci	uint32_t extra3;
3862306a36Sopenharmony_ci};
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistruct struct_test {
4162306a36Sopenharmony_ci	const char *name;
4262306a36Sopenharmony_ci	struct open_how_ext arg;
4362306a36Sopenharmony_ci	size_t size;
4462306a36Sopenharmony_ci	int err;
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define NUM_OPENAT2_STRUCT_TESTS 7
4862306a36Sopenharmony_ci#define NUM_OPENAT2_STRUCT_VARIATIONS 13
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_civoid test_openat2_struct(void)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	int misalignments[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 17, 87 };
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	struct struct_test tests[] = {
5562306a36Sopenharmony_ci		/* Normal struct. */
5662306a36Sopenharmony_ci		{ .name = "normal struct",
5762306a36Sopenharmony_ci		  .arg.inner.flags = O_RDONLY,
5862306a36Sopenharmony_ci		  .size = sizeof(struct open_how) },
5962306a36Sopenharmony_ci		/* Bigger struct, with zeroed out end. */
6062306a36Sopenharmony_ci		{ .name = "bigger struct (zeroed out)",
6162306a36Sopenharmony_ci		  .arg.inner.flags = O_RDONLY,
6262306a36Sopenharmony_ci		  .size = sizeof(struct open_how_ext) },
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci		/* TODO: Once expanded, check zero-padding. */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci		/* Smaller than version-0 struct. */
6762306a36Sopenharmony_ci		{ .name = "zero-sized 'struct'",
6862306a36Sopenharmony_ci		  .arg.inner.flags = O_RDONLY, .size = 0, .err = -EINVAL },
6962306a36Sopenharmony_ci		{ .name = "smaller-than-v0 struct",
7062306a36Sopenharmony_ci		  .arg.inner.flags = O_RDONLY,
7162306a36Sopenharmony_ci		  .size = OPEN_HOW_SIZE_VER0 - 1, .err = -EINVAL },
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci		/* Bigger struct, with non-zero trailing bytes. */
7462306a36Sopenharmony_ci		{ .name = "bigger struct (non-zero data in first 'future field')",
7562306a36Sopenharmony_ci		  .arg.inner.flags = O_RDONLY, .arg.extra1 = 0xdeadbeef,
7662306a36Sopenharmony_ci		  .size = sizeof(struct open_how_ext), .err = -E2BIG },
7762306a36Sopenharmony_ci		{ .name = "bigger struct (non-zero data in middle of 'future fields')",
7862306a36Sopenharmony_ci		  .arg.inner.flags = O_RDONLY, .arg.extra2 = 0xfeedcafe,
7962306a36Sopenharmony_ci		  .size = sizeof(struct open_how_ext), .err = -E2BIG },
8062306a36Sopenharmony_ci		{ .name = "bigger struct (non-zero data at end of 'future fields')",
8162306a36Sopenharmony_ci		  .arg.inner.flags = O_RDONLY, .arg.extra3 = 0xabad1dea,
8262306a36Sopenharmony_ci		  .size = sizeof(struct open_how_ext), .err = -E2BIG },
8362306a36Sopenharmony_ci	};
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	BUILD_BUG_ON(ARRAY_LEN(misalignments) != NUM_OPENAT2_STRUCT_VARIATIONS);
8662306a36Sopenharmony_ci	BUILD_BUG_ON(ARRAY_LEN(tests) != NUM_OPENAT2_STRUCT_TESTS);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	for (int i = 0; i < ARRAY_LEN(tests); i++) {
8962306a36Sopenharmony_ci		struct struct_test *test = &tests[i];
9062306a36Sopenharmony_ci		struct open_how_ext how_ext = test->arg;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci		for (int j = 0; j < ARRAY_LEN(misalignments); j++) {
9362306a36Sopenharmony_ci			int fd, misalign = misalignments[j];
9462306a36Sopenharmony_ci			char *fdpath = NULL;
9562306a36Sopenharmony_ci			bool failed;
9662306a36Sopenharmony_ci			void (*resultfn)(const char *msg, ...) = ksft_test_result_pass;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci			void *copy = NULL, *how_copy = &how_ext;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci			if (!openat2_supported) {
10162306a36Sopenharmony_ci				ksft_print_msg("openat2(2) unsupported\n");
10262306a36Sopenharmony_ci				resultfn = ksft_test_result_skip;
10362306a36Sopenharmony_ci				goto skip;
10462306a36Sopenharmony_ci			}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci			if (misalign) {
10762306a36Sopenharmony_ci				/*
10862306a36Sopenharmony_ci				 * Explicitly misalign the structure copying it with the given
10962306a36Sopenharmony_ci				 * (mis)alignment offset. The other data is set to be non-zero to
11062306a36Sopenharmony_ci				 * make sure that non-zero bytes outside the struct aren't checked
11162306a36Sopenharmony_ci				 *
11262306a36Sopenharmony_ci				 * This is effectively to check that is_zeroed_user() works.
11362306a36Sopenharmony_ci				 */
11462306a36Sopenharmony_ci				copy = malloc(misalign + sizeof(how_ext));
11562306a36Sopenharmony_ci				how_copy = copy + misalign;
11662306a36Sopenharmony_ci				memset(copy, 0xff, misalign);
11762306a36Sopenharmony_ci				memcpy(how_copy, &how_ext, sizeof(how_ext));
11862306a36Sopenharmony_ci			}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci			fd = raw_openat2(AT_FDCWD, ".", how_copy, test->size);
12162306a36Sopenharmony_ci			if (test->err >= 0)
12262306a36Sopenharmony_ci				failed = (fd < 0);
12362306a36Sopenharmony_ci			else
12462306a36Sopenharmony_ci				failed = (fd != test->err);
12562306a36Sopenharmony_ci			if (fd >= 0) {
12662306a36Sopenharmony_ci				fdpath = fdreadlink(fd);
12762306a36Sopenharmony_ci				close(fd);
12862306a36Sopenharmony_ci			}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci			if (failed) {
13162306a36Sopenharmony_ci				resultfn = ksft_test_result_fail;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci				ksft_print_msg("openat2 unexpectedly returned ");
13462306a36Sopenharmony_ci				if (fdpath)
13562306a36Sopenharmony_ci					ksft_print_msg("%d['%s']\n", fd, fdpath);
13662306a36Sopenharmony_ci				else
13762306a36Sopenharmony_ci					ksft_print_msg("%d (%s)\n", fd, strerror(-fd));
13862306a36Sopenharmony_ci			}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ciskip:
14162306a36Sopenharmony_ci			if (test->err >= 0)
14262306a36Sopenharmony_ci				resultfn("openat2 with %s argument [misalign=%d] succeeds\n",
14362306a36Sopenharmony_ci					 test->name, misalign);
14462306a36Sopenharmony_ci			else
14562306a36Sopenharmony_ci				resultfn("openat2 with %s argument [misalign=%d] fails with %d (%s)\n",
14662306a36Sopenharmony_ci					 test->name, misalign, test->err,
14762306a36Sopenharmony_ci					 strerror(-test->err));
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci			free(copy);
15062306a36Sopenharmony_ci			free(fdpath);
15162306a36Sopenharmony_ci			fflush(stdout);
15262306a36Sopenharmony_ci		}
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistruct flag_test {
15762306a36Sopenharmony_ci	const char *name;
15862306a36Sopenharmony_ci	struct open_how how;
15962306a36Sopenharmony_ci	int err;
16062306a36Sopenharmony_ci};
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci#define NUM_OPENAT2_FLAG_TESTS 25
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_civoid test_openat2_flags(void)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	struct flag_test tests[] = {
16762306a36Sopenharmony_ci		/* O_TMPFILE is incompatible with O_PATH and O_CREAT. */
16862306a36Sopenharmony_ci		{ .name = "incompatible flags (O_TMPFILE | O_PATH)",
16962306a36Sopenharmony_ci		  .how.flags = O_TMPFILE | O_PATH | O_RDWR, .err = -EINVAL },
17062306a36Sopenharmony_ci		{ .name = "incompatible flags (O_TMPFILE | O_CREAT)",
17162306a36Sopenharmony_ci		  .how.flags = O_TMPFILE | O_CREAT | O_RDWR, .err = -EINVAL },
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci		/* O_PATH only permits certain other flags to be set ... */
17462306a36Sopenharmony_ci		{ .name = "compatible flags (O_PATH | O_CLOEXEC)",
17562306a36Sopenharmony_ci		  .how.flags = O_PATH | O_CLOEXEC },
17662306a36Sopenharmony_ci		{ .name = "compatible flags (O_PATH | O_DIRECTORY)",
17762306a36Sopenharmony_ci		  .how.flags = O_PATH | O_DIRECTORY },
17862306a36Sopenharmony_ci		{ .name = "compatible flags (O_PATH | O_NOFOLLOW)",
17962306a36Sopenharmony_ci		  .how.flags = O_PATH | O_NOFOLLOW },
18062306a36Sopenharmony_ci		/* ... and others are absolutely not permitted. */
18162306a36Sopenharmony_ci		{ .name = "incompatible flags (O_PATH | O_RDWR)",
18262306a36Sopenharmony_ci		  .how.flags = O_PATH | O_RDWR, .err = -EINVAL },
18362306a36Sopenharmony_ci		{ .name = "incompatible flags (O_PATH | O_CREAT)",
18462306a36Sopenharmony_ci		  .how.flags = O_PATH | O_CREAT, .err = -EINVAL },
18562306a36Sopenharmony_ci		{ .name = "incompatible flags (O_PATH | O_EXCL)",
18662306a36Sopenharmony_ci		  .how.flags = O_PATH | O_EXCL, .err = -EINVAL },
18762306a36Sopenharmony_ci		{ .name = "incompatible flags (O_PATH | O_NOCTTY)",
18862306a36Sopenharmony_ci		  .how.flags = O_PATH | O_NOCTTY, .err = -EINVAL },
18962306a36Sopenharmony_ci		{ .name = "incompatible flags (O_PATH | O_DIRECT)",
19062306a36Sopenharmony_ci		  .how.flags = O_PATH | O_DIRECT, .err = -EINVAL },
19162306a36Sopenharmony_ci		{ .name = "incompatible flags (O_PATH | O_LARGEFILE)",
19262306a36Sopenharmony_ci		  .how.flags = O_PATH | O_LARGEFILE, .err = -EINVAL },
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci		/* ->mode must only be set with O_{CREAT,TMPFILE}. */
19562306a36Sopenharmony_ci		{ .name = "non-zero how.mode and O_RDONLY",
19662306a36Sopenharmony_ci		  .how.flags = O_RDONLY, .how.mode = 0600, .err = -EINVAL },
19762306a36Sopenharmony_ci		{ .name = "non-zero how.mode and O_PATH",
19862306a36Sopenharmony_ci		  .how.flags = O_PATH,   .how.mode = 0600, .err = -EINVAL },
19962306a36Sopenharmony_ci		{ .name = "valid how.mode and O_CREAT",
20062306a36Sopenharmony_ci		  .how.flags = O_CREAT,  .how.mode = 0600 },
20162306a36Sopenharmony_ci		{ .name = "valid how.mode and O_TMPFILE",
20262306a36Sopenharmony_ci		  .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0600 },
20362306a36Sopenharmony_ci		/* ->mode must only contain 0777 bits. */
20462306a36Sopenharmony_ci		{ .name = "invalid how.mode and O_CREAT",
20562306a36Sopenharmony_ci		  .how.flags = O_CREAT,
20662306a36Sopenharmony_ci		  .how.mode = 0xFFFF, .err = -EINVAL },
20762306a36Sopenharmony_ci		{ .name = "invalid (very large) how.mode and O_CREAT",
20862306a36Sopenharmony_ci		  .how.flags = O_CREAT,
20962306a36Sopenharmony_ci		  .how.mode = 0xC000000000000000ULL, .err = -EINVAL },
21062306a36Sopenharmony_ci		{ .name = "invalid how.mode and O_TMPFILE",
21162306a36Sopenharmony_ci		  .how.flags = O_TMPFILE | O_RDWR,
21262306a36Sopenharmony_ci		  .how.mode = 0x1337, .err = -EINVAL },
21362306a36Sopenharmony_ci		{ .name = "invalid (very large) how.mode and O_TMPFILE",
21462306a36Sopenharmony_ci		  .how.flags = O_TMPFILE | O_RDWR,
21562306a36Sopenharmony_ci		  .how.mode = 0x0000A00000000000ULL, .err = -EINVAL },
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		/* ->resolve flags must not conflict. */
21862306a36Sopenharmony_ci		{ .name = "incompatible resolve flags (BENEATH | IN_ROOT)",
21962306a36Sopenharmony_ci		  .how.flags = O_RDONLY,
22062306a36Sopenharmony_ci		  .how.resolve = RESOLVE_BENEATH | RESOLVE_IN_ROOT,
22162306a36Sopenharmony_ci		  .err = -EINVAL },
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci		/* ->resolve must only contain RESOLVE_* flags. */
22462306a36Sopenharmony_ci		{ .name = "invalid how.resolve and O_RDONLY",
22562306a36Sopenharmony_ci		  .how.flags = O_RDONLY,
22662306a36Sopenharmony_ci		  .how.resolve = 0x1337, .err = -EINVAL },
22762306a36Sopenharmony_ci		{ .name = "invalid how.resolve and O_CREAT",
22862306a36Sopenharmony_ci		  .how.flags = O_CREAT,
22962306a36Sopenharmony_ci		  .how.resolve = 0x1337, .err = -EINVAL },
23062306a36Sopenharmony_ci		{ .name = "invalid how.resolve and O_TMPFILE",
23162306a36Sopenharmony_ci		  .how.flags = O_TMPFILE | O_RDWR,
23262306a36Sopenharmony_ci		  .how.resolve = 0x1337, .err = -EINVAL },
23362306a36Sopenharmony_ci		{ .name = "invalid how.resolve and O_PATH",
23462306a36Sopenharmony_ci		  .how.flags = O_PATH,
23562306a36Sopenharmony_ci		  .how.resolve = 0x1337, .err = -EINVAL },
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci		/* currently unknown upper 32 bit rejected. */
23862306a36Sopenharmony_ci		{ .name = "currently unknown bit (1 << 63)",
23962306a36Sopenharmony_ci		  .how.flags = O_RDONLY | (1ULL << 63),
24062306a36Sopenharmony_ci		  .how.resolve = 0, .err = -EINVAL },
24162306a36Sopenharmony_ci	};
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	BUILD_BUG_ON(ARRAY_LEN(tests) != NUM_OPENAT2_FLAG_TESTS);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	for (int i = 0; i < ARRAY_LEN(tests); i++) {
24662306a36Sopenharmony_ci		int fd, fdflags = -1;
24762306a36Sopenharmony_ci		char *path, *fdpath = NULL;
24862306a36Sopenharmony_ci		bool failed = false;
24962306a36Sopenharmony_ci		struct flag_test *test = &tests[i];
25062306a36Sopenharmony_ci		void (*resultfn)(const char *msg, ...) = ksft_test_result_pass;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci		if (!openat2_supported) {
25362306a36Sopenharmony_ci			ksft_print_msg("openat2(2) unsupported\n");
25462306a36Sopenharmony_ci			resultfn = ksft_test_result_skip;
25562306a36Sopenharmony_ci			goto skip;
25662306a36Sopenharmony_ci		}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		path = (test->how.flags & O_CREAT) ? "/tmp/ksft.openat2_tmpfile" : ".";
25962306a36Sopenharmony_ci		unlink(path);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		fd = sys_openat2(AT_FDCWD, path, &test->how);
26262306a36Sopenharmony_ci		if (fd < 0 && fd == -EOPNOTSUPP) {
26362306a36Sopenharmony_ci			/*
26462306a36Sopenharmony_ci			 * Skip the testcase if it failed because not supported
26562306a36Sopenharmony_ci			 * by FS. (e.g. a valid O_TMPFILE combination on NFS)
26662306a36Sopenharmony_ci			 */
26762306a36Sopenharmony_ci			ksft_test_result_skip("openat2 with %s fails with %d (%s)\n",
26862306a36Sopenharmony_ci					      test->name, fd, strerror(-fd));
26962306a36Sopenharmony_ci			goto next;
27062306a36Sopenharmony_ci		}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		if (test->err >= 0)
27362306a36Sopenharmony_ci			failed = (fd < 0);
27462306a36Sopenharmony_ci		else
27562306a36Sopenharmony_ci			failed = (fd != test->err);
27662306a36Sopenharmony_ci		if (fd >= 0) {
27762306a36Sopenharmony_ci			int otherflags;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci			fdpath = fdreadlink(fd);
28062306a36Sopenharmony_ci			fdflags = fcntl(fd, F_GETFL);
28162306a36Sopenharmony_ci			otherflags = fcntl(fd, F_GETFD);
28262306a36Sopenharmony_ci			close(fd);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci			E_assert(fdflags >= 0, "fcntl F_GETFL of new fd");
28562306a36Sopenharmony_ci			E_assert(otherflags >= 0, "fcntl F_GETFD of new fd");
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci			/* O_CLOEXEC isn't shown in F_GETFL. */
28862306a36Sopenharmony_ci			if (otherflags & FD_CLOEXEC)
28962306a36Sopenharmony_ci				fdflags |= O_CLOEXEC;
29062306a36Sopenharmony_ci			/* O_CREAT is hidden from F_GETFL. */
29162306a36Sopenharmony_ci			if (test->how.flags & O_CREAT)
29262306a36Sopenharmony_ci				fdflags |= O_CREAT;
29362306a36Sopenharmony_ci			if (!(test->how.flags & O_LARGEFILE))
29462306a36Sopenharmony_ci				fdflags &= ~O_LARGEFILE;
29562306a36Sopenharmony_ci			failed |= (fdflags != test->how.flags);
29662306a36Sopenharmony_ci		}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci		if (failed) {
29962306a36Sopenharmony_ci			resultfn = ksft_test_result_fail;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci			ksft_print_msg("openat2 unexpectedly returned ");
30262306a36Sopenharmony_ci			if (fdpath)
30362306a36Sopenharmony_ci				ksft_print_msg("%d['%s'] with %X (!= %X)\n",
30462306a36Sopenharmony_ci					       fd, fdpath, fdflags,
30562306a36Sopenharmony_ci					       test->how.flags);
30662306a36Sopenharmony_ci			else
30762306a36Sopenharmony_ci				ksft_print_msg("%d (%s)\n", fd, strerror(-fd));
30862306a36Sopenharmony_ci		}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ciskip:
31162306a36Sopenharmony_ci		if (test->err >= 0)
31262306a36Sopenharmony_ci			resultfn("openat2 with %s succeeds\n", test->name);
31362306a36Sopenharmony_ci		else
31462306a36Sopenharmony_ci			resultfn("openat2 with %s fails with %d (%s)\n",
31562306a36Sopenharmony_ci				 test->name, test->err, strerror(-test->err));
31662306a36Sopenharmony_cinext:
31762306a36Sopenharmony_ci		free(fdpath);
31862306a36Sopenharmony_ci		fflush(stdout);
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci#define NUM_TESTS (NUM_OPENAT2_STRUCT_VARIATIONS * NUM_OPENAT2_STRUCT_TESTS + \
32362306a36Sopenharmony_ci		   NUM_OPENAT2_FLAG_TESTS)
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ciint main(int argc, char **argv)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	ksft_print_header();
32862306a36Sopenharmony_ci	ksft_set_plan(NUM_TESTS);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	test_openat2_struct();
33162306a36Sopenharmony_ci	test_openat2_flags();
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (ksft_get_fail_cnt() + ksft_get_error_cnt() > 0)
33462306a36Sopenharmony_ci		ksft_exit_fail();
33562306a36Sopenharmony_ci	else
33662306a36Sopenharmony_ci		ksft_exit_pass();
33762306a36Sopenharmony_ci}
338