1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2015 Cedric Hnyda <chnyda@suse.com>
4 */
5
6 /* Description:
7 *   Verify that:
8 *		1) kcmp returns 0 with two process and two fd refering to the
9 *			same open file
10 *		2) kcmp doesn't return 0 with two process and two fd not
11 *		   refering to the same open file
12 */
13
14#define _GNU_SOURCE
15
16#include "tst_test.h"
17#include "lapi/fcntl.h"
18#include "lapi/kcmp.h"
19
20#define TEST_FILE "test_file"
21#define TEST_FILE2 "test_file2"
22
23static int fd1;
24static int fd2;
25static int fd3;
26static int pid1;
27static int pid2;
28
29static struct test_case {
30	int *pid1;
31	int *pid2;
32	int type;
33	int *fd1;
34	int *fd2;
35	int exp_different;
36} test_cases[] = {
37	{&pid1, &pid1, KCMP_FILE, &fd1, &fd1, 0},
38	{&pid2, &pid2, KCMP_FILE, &fd1, &fd2, 0},
39	{&pid1, &pid2, KCMP_FILE, &fd1, &fd1, 0},
40	{&pid1, &pid2, KCMP_FILE, &fd1, &fd2, 0},
41	{&pid1, &pid2, KCMP_FILE, &fd1, &fd3, 1},
42};
43
44static void setup(void)
45{
46	fd1 = SAFE_OPEN(TEST_FILE, O_CREAT | O_RDWR | O_TRUNC, 0666);
47}
48
49static void cleanup(void)
50{
51	if (fd1 > 0)
52		SAFE_CLOSE(fd1);
53}
54
55static void do_child(const struct test_case *test)
56{
57	pid2 = getpid();
58
59	fd3 = SAFE_OPEN(TEST_FILE2, O_CREAT | O_RDWR, 0666);
60
61	fd2 = dup(fd1);
62	if (fd2 == -1) {
63		tst_res(TFAIL | TERRNO, "dup() failed unexpectedly");
64		SAFE_CLOSE(fd3);
65		return;
66	}
67
68	TEST(kcmp(*(test->pid1), *(test->pid2), test->type,
69		  *(test->fd1), *(test->fd2)));
70
71	SAFE_CLOSE(fd2);
72	SAFE_CLOSE(fd3);
73
74	if (TST_RET == -1) {
75		tst_res(TFAIL | TTERRNO, "kcmp() failed unexpectedly");
76		return;
77	}
78
79	if ((test->exp_different && TST_RET == 0)
80		|| (test->exp_different == 0 && TST_RET)) {
81		tst_res(TFAIL, "kcmp() returned %lu instead of %d",
82			TST_RET, test->exp_different);
83		return;
84	}
85
86	tst_res(TPASS, "kcmp() returned the expected value");
87}
88
89static void verify_kcmp(unsigned int n)
90{
91	struct test_case *tc = &test_cases[n];
92
93	pid1 = getpid();
94
95	pid2 = SAFE_FORK();
96	if (!pid2)
97		do_child(tc);
98}
99
100static struct tst_test test = {
101	.tcnt = ARRAY_SIZE(test_cases),
102	.setup = setup,
103	.cleanup = cleanup,
104	.forks_child = 1,
105	.test = verify_kcmp,
106	.needs_tmpdir = 1,
107};
108