1 /* $OpenBSD: kqueue-exec.c,v 1.1 2023/08/20 15:19:34 visa Exp $ */ 2 3 /* 4 * Copyright (c) 2023 Visa Hankala 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/event.h> 21 #include <sys/time.h> 22 #include <sys/wait.h> 23 #include <err.h> 24 #include <errno.h> 25 #include <fcntl.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 #include "main.h" 32 33 static void do_exec_child(void); 34 static void do_exec_parent(const char *, int); 35 36 int 37 do_exec(const char *argv0) 38 { 39 do_exec_parent(argv0, 0); 40 do_exec_parent(argv0, 1); 41 return 0; 42 } 43 44 static void 45 do_exec_parent(const char *argv0, int cloexec) 46 { 47 char *args[] = { 48 (char *)argv0, 49 "-e", 50 NULL 51 }; 52 char fdbuf[12]; 53 pid_t pid; 54 int kq, status; 55 56 if (getenv("REGRESS_KQUEUE_FD") != NULL) { 57 do_exec_child(); 58 _exit(0); 59 } 60 61 pid = fork(); 62 if (pid == -1) 63 err(1, "fork"); 64 if (pid == 0) { 65 kq = kqueue1(cloexec ? O_CLOEXEC : 0); 66 if (kq == -1) 67 err(1, "kqueue1"); 68 snprintf(fdbuf, sizeof(fdbuf), "%d", kq); 69 if (setenv("REGRESS_KQUEUE_FD", fdbuf, 1) == -1) 70 err(1, "setenv"); 71 if (setenv("REGRESS_KQUEUE_CLOEXEC", 72 cloexec ? "1" : "0", 1) == -1) 73 err(1, "setenv 2"); 74 execv(argv0, args); 75 err(1, "execve"); 76 } 77 if (waitpid(pid, &status, 0) == -1) 78 err(1, "waitpid"); 79 if (status != 0) 80 errx(1, "child failed"); 81 } 82 83 static void 84 do_exec_child(void) 85 { 86 char *arg; 87 int cloexec, fd; 88 89 arg = getenv("REGRESS_KQUEUE_FD"); 90 if (arg == NULL) 91 errx(1, "fd arg is missing"); 92 fd = atoi(arg); 93 94 arg = getenv("REGRESS_KQUEUE_CLOEXEC"); 95 if (arg != NULL && strcmp(arg, "1") == 0) 96 cloexec = 1; 97 else 98 cloexec = 0; 99 100 if (cloexec) { 101 if (kevent(fd, NULL, 0, NULL, 0, 0) == -1) { 102 if (errno != EBADF) 103 err(1, "child after exec: kevent cloexec"); 104 } else { 105 errx(1, "child after exec: " 106 "kqueue cloexec fd is not closed"); 107 } 108 } else { 109 if (kevent(fd, NULL, 0, NULL, 0, 0) == -1) { 110 err(1, "child after exec: kevent"); 111 } 112 } 113 } 114