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(3); 93 94 fd2 = open(kpath, O_RDWR); 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, KCMP_FILE, fd1, fd2), 106 sys_kcmp(pid1, pid2, KCMP_FILES, 0, 0), 107 sys_kcmp(pid1, pid2, KCMP_VM, 0, 0), 108 sys_kcmp(pid1, pid2, KCMP_FS, 0, 0), 109 sys_kcmp(pid1, pid2, KCMP_SIGHAND, 0, 0), 110 sys_kcmp(pid1, pid2, KCMP_IO, 0, 0), 111 sys_kcmp(pid1, pid2, KCMP_SYSVSEM, 0, 0), 112 113 /* This one should fail */ 114 sys_kcmp(pid1, pid2, KCMP_TYPES + 1, 0, 0)); 115 116 /* This one should return same fd */ 117 ret = sys_kcmp(pid1, pid2, KCMP_FILE, fd1, 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, pid1, KCMP_VM, 0, 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, pid1, KCMP_EPOLL_TFD, pipefd[1], 147 (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