1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #define _GNU_SOURCE |
3 | |
4 | #include <stdio.h> |
5 | #include <stdlib.h> |
6 | #include <signal.h> |
7 | #include <limits.h> |
8 | #include <unistd.h> |
9 | #include <errno.h> |
10 | #include <string.h> |
11 | #include <fcntl.h> |
12 | #include <linux/unistd.h> |
13 | #include <linux/kcmp.h> |
14 | |
15 | #include <sys/syscall.h> |
16 | #include <sys/types.h> |
17 | #include <sys/stat.h> |
18 | #include <sys/wait.h> |
19 | #include <sys/epoll.h> |
20 | |
21 | #include "../kselftest.h" |
22 | |
23 | static long sys_kcmp(int pid1, int pid2, int type, unsigned long fd1, unsigned long fd2) |
24 | { |
25 | return syscall(__NR_kcmp, pid1, pid2, type, fd1, fd2); |
26 | } |
27 | |
28 | static const unsigned int duped_num = 64; |
29 | |
30 | int main(int argc, char **argv) |
31 | { |
32 | const char kpath[] = "kcmp-test-file" ; |
33 | struct kcmp_epoll_slot epoll_slot; |
34 | struct epoll_event ev; |
35 | int pid1, pid2; |
36 | int pipefd[2]; |
37 | int fd1, fd2; |
38 | int epollfd; |
39 | int status; |
40 | int fddup; |
41 | |
42 | fd1 = open(kpath, O_RDWR | O_CREAT | O_TRUNC, 0644); |
43 | pid1 = getpid(); |
44 | |
45 | if (fd1 < 0) { |
46 | perror("Can't create file" ); |
47 | ksft_exit_fail(); |
48 | } |
49 | |
50 | if (pipe(pipefd)) { |
51 | perror("Can't create pipe" ); |
52 | ksft_exit_fail(); |
53 | } |
54 | |
55 | epollfd = epoll_create1(0); |
56 | if (epollfd < 0) { |
57 | perror("epoll_create1 failed" ); |
58 | ksft_exit_fail(); |
59 | } |
60 | |
61 | memset(&ev, 0xff, sizeof(ev)); |
62 | ev.events = EPOLLIN | EPOLLOUT; |
63 | |
64 | if (epoll_ctl(epollfd, EPOLL_CTL_ADD, pipefd[0], &ev)) { |
65 | perror("epoll_ctl failed" ); |
66 | ksft_exit_fail(); |
67 | } |
68 | |
69 | fddup = dup2(pipefd[1], duped_num); |
70 | if (fddup < 0) { |
71 | perror("dup2 failed" ); |
72 | ksft_exit_fail(); |
73 | } |
74 | |
75 | if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fddup, &ev)) { |
76 | perror("epoll_ctl failed" ); |
77 | ksft_exit_fail(); |
78 | } |
79 | close(fddup); |
80 | |
81 | pid2 = fork(); |
82 | if (pid2 < 0) { |
83 | perror("fork failed" ); |
84 | ksft_exit_fail(); |
85 | } |
86 | |
87 | if (!pid2) { |
88 | int pid2 = getpid(); |
89 | int ret; |
90 | |
91 | ksft_print_header(); |
92 | ksft_set_plan(plan: 3); |
93 | |
94 | fd2 = open(kpath, O_RDWR, 0644); |
95 | if (fd2 < 0) { |
96 | perror("Can't open file" ); |
97 | ksft_exit_fail(); |
98 | } |
99 | |
100 | /* An example of output and arguments */ |
101 | printf("pid1: %6d pid2: %6d FD: %2ld FILES: %2ld VM: %2ld " |
102 | "FS: %2ld SIGHAND: %2ld IO: %2ld SYSVSEM: %2ld " |
103 | "INV: %2ld\n" , |
104 | pid1, pid2, |
105 | sys_kcmp(pid1, pid2, type: KCMP_FILE, fd1, fd2), |
106 | sys_kcmp(pid1, pid2, type: KCMP_FILES, fd1: 0, fd2: 0), |
107 | sys_kcmp(pid1, pid2, type: KCMP_VM, fd1: 0, fd2: 0), |
108 | sys_kcmp(pid1, pid2, type: KCMP_FS, fd1: 0, fd2: 0), |
109 | sys_kcmp(pid1, pid2, type: KCMP_SIGHAND, fd1: 0, fd2: 0), |
110 | sys_kcmp(pid1, pid2, type: KCMP_IO, fd1: 0, fd2: 0), |
111 | sys_kcmp(pid1, pid2, type: KCMP_SYSVSEM, fd1: 0, fd2: 0), |
112 | |
113 | /* This one should fail */ |
114 | sys_kcmp(pid1, pid2, type: KCMP_TYPES + 1, fd1: 0, fd2: 0)); |
115 | |
116 | /* This one should return same fd */ |
117 | ret = sys_kcmp(pid1, pid2, type: KCMP_FILE, fd1, fd2: fd1); |
118 | if (ret) { |
119 | printf("FAIL: 0 expected but %d returned (%s)\n" , |
120 | ret, strerror(errno)); |
121 | ksft_inc_fail_cnt(); |
122 | ret = -1; |
123 | } else { |
124 | printf("PASS: 0 returned as expected\n" ); |
125 | ksft_inc_pass_cnt(); |
126 | } |
127 | |
128 | /* Compare with self */ |
129 | ret = sys_kcmp(pid1, pid2: pid1, type: KCMP_VM, fd1: 0, fd2: 0); |
130 | if (ret) { |
131 | printf("FAIL: 0 expected but %d returned (%s)\n" , |
132 | ret, strerror(errno)); |
133 | ksft_inc_fail_cnt(); |
134 | ret = -1; |
135 | } else { |
136 | printf("PASS: 0 returned as expected\n" ); |
137 | ksft_inc_pass_cnt(); |
138 | } |
139 | |
140 | /* Compare epoll target */ |
141 | epoll_slot = (struct kcmp_epoll_slot) { |
142 | .efd = epollfd, |
143 | .tfd = duped_num, |
144 | .toff = 0, |
145 | }; |
146 | ret = sys_kcmp(pid1, pid2: pid1, type: KCMP_EPOLL_TFD, fd1: pipefd[1], |
147 | fd2: (unsigned long)(void *)&epoll_slot); |
148 | if (ret) { |
149 | printf("FAIL: 0 expected but %d returned (%s)\n" , |
150 | ret, strerror(errno)); |
151 | ksft_inc_fail_cnt(); |
152 | ret = -1; |
153 | } else { |
154 | printf("PASS: 0 returned as expected\n" ); |
155 | ksft_inc_pass_cnt(); |
156 | } |
157 | |
158 | |
159 | if (ret) |
160 | ksft_exit_fail(); |
161 | else |
162 | ksft_exit_pass(); |
163 | } |
164 | |
165 | waitpid(pid2, &status, P_ALL); |
166 | |
167 | return 0; |
168 | } |
169 | |