1 #include <sys/types.h> 2 #include <sys/socket.h> 3 #include <sys/wait.h> 4 5 #include <arpa/inet.h> 6 #include <netinet/in.h> 7 8 #include <err.h> 9 #include <errno.h> 10 #include <signal.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <unistd.h> 15 16 #define CHECKFD_CMD "checkfd" 17 #define CHECKFD_PATH "/usr/local/bin/" CHECKFD_CMD 18 19 static void 20 usage(const char *cmd) 21 { 22 fprintf(stderr, "%s -p port\n", cmd); 23 exit(1); 24 } 25 26 static void 27 connect_client(int port) 28 { 29 struct sockaddr_in in; 30 int s; 31 32 memset(&in, 0, sizeof(in)); 33 in.sin_family = AF_INET; 34 in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 35 in.sin_port = htons(port); 36 37 s = socket(AF_INET, SOCK_STREAM, 0); 38 if (s < 0) 39 err(1, "client socket failed"); 40 if (connect(s, (const struct sockaddr *)&in, sizeof(in)) < 0) 41 err(1, "connect failed"); 42 43 pause(); 44 exit(0); 45 } 46 47 int 48 main(int argc, char *argv[]) 49 { 50 pid_t pid; 51 struct sockaddr_in in; 52 int serv_s, s; 53 int opt, port, status, ecode, error; 54 55 port = 0; 56 while ((opt = getopt(argc, argv, "p:")) != -1) { 57 char *endptr; 58 59 switch (opt) { 60 case 'p': 61 port = strtol(optarg, &endptr, 0); 62 if (*endptr != '\0') 63 errx(1, "invalid -p %s", optarg); 64 break; 65 66 default: 67 usage(argv[0]); 68 } 69 } 70 if (port <= 0) 71 usage(argv[0]); 72 73 serv_s = socket(AF_INET, SOCK_STREAM, 0); 74 if (serv_s < 0) 75 err(1, "socket failed"); 76 77 memset(&in, 0, sizeof(in)); 78 in.sin_family = AF_INET; 79 in.sin_port = htons(port); 80 if (bind(serv_s, (const struct sockaddr *)&in, sizeof(in)) < 0) 81 err(1, "bind failed"); 82 83 if (listen(serv_s, 0) < 0) 84 err(1, "listen failed"); 85 86 pid = fork(); 87 if (pid < 0) { 88 err(1, "fork failed"); 89 } else if (pid == 0) { 90 connect_client(port); 91 abort(); 92 /* NEVER REACHED */ 93 } 94 95 s = accept4(serv_s, NULL, NULL, SOCK_CLOEXEC); 96 if (s < 0) 97 error = errno; 98 else 99 error = 0; 100 101 /* Kill connect_client */ 102 kill(pid, SIGKILL); 103 waitpid(pid, &status, 0); 104 105 if (error) 106 errc(1, error, "accept4 failed"); 107 108 pid = fork(); 109 if (pid < 0) { 110 err(1, "fork failed"); 111 } else if (pid == 0) { 112 char fd[8]; 113 114 snprintf(fd, sizeof(fd), "%d", s); 115 execl(CHECKFD_PATH, CHECKFD_CMD, fd, NULL); 116 } 117 118 if (waitpid(pid, &status, 0) < 0) 119 err(1, "waitpid failed"); 120 if (!WIFEXITED(status)) 121 errx(1, "not exited"); 122 ecode = WEXITSTATUS(status); 123 if (ecode != 0) { 124 warnx("exit code %d", ecode); 125 abort(); 126 } 127 128 fprintf(stderr, "passed\n"); 129 exit(0); 130 } 131