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
do_exec(const char * argv0)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
do_exec_parent(const char * argv0,int cloexec)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
do_exec_child(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