162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#define _GNU_SOURCE
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <stdio.h>
562306a36Sopenharmony_ci#include <stdlib.h>
662306a36Sopenharmony_ci#include <signal.h>
762306a36Sopenharmony_ci#include <limits.h>
862306a36Sopenharmony_ci#include <unistd.h>
962306a36Sopenharmony_ci#include <errno.h>
1062306a36Sopenharmony_ci#include <string.h>
1162306a36Sopenharmony_ci#include <fcntl.h>
1262306a36Sopenharmony_ci#include <linux/unistd.h>
1362306a36Sopenharmony_ci#include <linux/kcmp.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <sys/syscall.h>
1662306a36Sopenharmony_ci#include <sys/types.h>
1762306a36Sopenharmony_ci#include <sys/stat.h>
1862306a36Sopenharmony_ci#include <sys/wait.h>
1962306a36Sopenharmony_ci#include <sys/epoll.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "../kselftest.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic long sys_kcmp(int pid1, int pid2, int type, unsigned long fd1, unsigned long fd2)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	return syscall(__NR_kcmp, pid1, pid2, type, fd1, fd2);
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic const unsigned int duped_num = 64;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ciint main(int argc, char **argv)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	const char kpath[] = "kcmp-test-file";
3362306a36Sopenharmony_ci	struct kcmp_epoll_slot epoll_slot;
3462306a36Sopenharmony_ci	struct epoll_event ev;
3562306a36Sopenharmony_ci	int pid1, pid2;
3662306a36Sopenharmony_ci	int pipefd[2];
3762306a36Sopenharmony_ci	int fd1, fd2;
3862306a36Sopenharmony_ci	int epollfd;
3962306a36Sopenharmony_ci	int status;
4062306a36Sopenharmony_ci	int fddup;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	fd1 = open(kpath, O_RDWR | O_CREAT | O_TRUNC, 0644);
4362306a36Sopenharmony_ci	pid1 = getpid();
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	if (fd1 < 0) {
4662306a36Sopenharmony_ci		perror("Can't create file");
4762306a36Sopenharmony_ci		ksft_exit_fail();
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (pipe(pipefd)) {
5162306a36Sopenharmony_ci		perror("Can't create pipe");
5262306a36Sopenharmony_ci		ksft_exit_fail();
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	epollfd = epoll_create1(0);
5662306a36Sopenharmony_ci	if (epollfd < 0) {
5762306a36Sopenharmony_ci		perror("epoll_create1 failed");
5862306a36Sopenharmony_ci		ksft_exit_fail();
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	memset(&ev, 0xff, sizeof(ev));
6262306a36Sopenharmony_ci	ev.events = EPOLLIN | EPOLLOUT;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, pipefd[0], &ev)) {
6562306a36Sopenharmony_ci		perror("epoll_ctl failed");
6662306a36Sopenharmony_ci		ksft_exit_fail();
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	fddup = dup2(pipefd[1], duped_num);
7062306a36Sopenharmony_ci	if (fddup < 0) {
7162306a36Sopenharmony_ci		perror("dup2 failed");
7262306a36Sopenharmony_ci		ksft_exit_fail();
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fddup, &ev)) {
7662306a36Sopenharmony_ci		perror("epoll_ctl failed");
7762306a36Sopenharmony_ci		ksft_exit_fail();
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci	close(fddup);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	pid2 = fork();
8262306a36Sopenharmony_ci	if (pid2 < 0) {
8362306a36Sopenharmony_ci		perror("fork failed");
8462306a36Sopenharmony_ci		ksft_exit_fail();
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (!pid2) {
8862306a36Sopenharmony_ci		int pid2 = getpid();
8962306a36Sopenharmony_ci		int ret;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci		ksft_print_header();
9262306a36Sopenharmony_ci		ksft_set_plan(3);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci		fd2 = open(kpath, O_RDWR, 0644);
9562306a36Sopenharmony_ci		if (fd2 < 0) {
9662306a36Sopenharmony_ci			perror("Can't open file");
9762306a36Sopenharmony_ci			ksft_exit_fail();
9862306a36Sopenharmony_ci		}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		/* An example of output and arguments */
10162306a36Sopenharmony_ci		printf("pid1: %6d pid2: %6d FD: %2ld FILES: %2ld VM: %2ld "
10262306a36Sopenharmony_ci		       "FS: %2ld SIGHAND: %2ld IO: %2ld SYSVSEM: %2ld "
10362306a36Sopenharmony_ci		       "INV: %2ld\n",
10462306a36Sopenharmony_ci		       pid1, pid2,
10562306a36Sopenharmony_ci		       sys_kcmp(pid1, pid2, KCMP_FILE,		fd1, fd2),
10662306a36Sopenharmony_ci		       sys_kcmp(pid1, pid2, KCMP_FILES,		0, 0),
10762306a36Sopenharmony_ci		       sys_kcmp(pid1, pid2, KCMP_VM,		0, 0),
10862306a36Sopenharmony_ci		       sys_kcmp(pid1, pid2, KCMP_FS,		0, 0),
10962306a36Sopenharmony_ci		       sys_kcmp(pid1, pid2, KCMP_SIGHAND,	0, 0),
11062306a36Sopenharmony_ci		       sys_kcmp(pid1, pid2, KCMP_IO,		0, 0),
11162306a36Sopenharmony_ci		       sys_kcmp(pid1, pid2, KCMP_SYSVSEM,	0, 0),
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci			/* This one should fail */
11462306a36Sopenharmony_ci		       sys_kcmp(pid1, pid2, KCMP_TYPES + 1,	0, 0));
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci		/* This one should return same fd */
11762306a36Sopenharmony_ci		ret = sys_kcmp(pid1, pid2, KCMP_FILE, fd1, fd1);
11862306a36Sopenharmony_ci		if (ret) {
11962306a36Sopenharmony_ci			printf("FAIL: 0 expected but %d returned (%s)\n",
12062306a36Sopenharmony_ci				ret, strerror(errno));
12162306a36Sopenharmony_ci			ksft_inc_fail_cnt();
12262306a36Sopenharmony_ci			ret = -1;
12362306a36Sopenharmony_ci		} else {
12462306a36Sopenharmony_ci			printf("PASS: 0 returned as expected\n");
12562306a36Sopenharmony_ci			ksft_inc_pass_cnt();
12662306a36Sopenharmony_ci		}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		/* Compare with self */
12962306a36Sopenharmony_ci		ret = sys_kcmp(pid1, pid1, KCMP_VM, 0, 0);
13062306a36Sopenharmony_ci		if (ret) {
13162306a36Sopenharmony_ci			printf("FAIL: 0 expected but %d returned (%s)\n",
13262306a36Sopenharmony_ci				ret, strerror(errno));
13362306a36Sopenharmony_ci			ksft_inc_fail_cnt();
13462306a36Sopenharmony_ci			ret = -1;
13562306a36Sopenharmony_ci		} else {
13662306a36Sopenharmony_ci			printf("PASS: 0 returned as expected\n");
13762306a36Sopenharmony_ci			ksft_inc_pass_cnt();
13862306a36Sopenharmony_ci		}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci		/* Compare epoll target */
14162306a36Sopenharmony_ci		epoll_slot = (struct kcmp_epoll_slot) {
14262306a36Sopenharmony_ci			.efd	= epollfd,
14362306a36Sopenharmony_ci			.tfd	= duped_num,
14462306a36Sopenharmony_ci			.toff	= 0,
14562306a36Sopenharmony_ci		};
14662306a36Sopenharmony_ci		ret = sys_kcmp(pid1, pid1, KCMP_EPOLL_TFD, pipefd[1],
14762306a36Sopenharmony_ci			       (unsigned long)(void *)&epoll_slot);
14862306a36Sopenharmony_ci		if (ret) {
14962306a36Sopenharmony_ci			printf("FAIL: 0 expected but %d returned (%s)\n",
15062306a36Sopenharmony_ci				ret, strerror(errno));
15162306a36Sopenharmony_ci			ksft_inc_fail_cnt();
15262306a36Sopenharmony_ci			ret = -1;
15362306a36Sopenharmony_ci		} else {
15462306a36Sopenharmony_ci			printf("PASS: 0 returned as expected\n");
15562306a36Sopenharmony_ci			ksft_inc_pass_cnt();
15662306a36Sopenharmony_ci		}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci		if (ret)
16062306a36Sopenharmony_ci			ksft_exit_fail();
16162306a36Sopenharmony_ci		else
16262306a36Sopenharmony_ci			ksft_exit_pass();
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	waitpid(pid2, &status, P_ALL);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return 0;
16862306a36Sopenharmony_ci}
169