xref: /illumos-gate/usr/src/test/os-tests/tests/oclo/ocloexec_verify.c (revision 0250c53ad267726f2438e3c6556199a0bbf588a2)
1*0250c53aSRobert Mustacchi /*
2*0250c53aSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*0250c53aSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*0250c53aSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*0250c53aSRobert Mustacchi  * 1.0 of the CDDL.
6*0250c53aSRobert Mustacchi  *
7*0250c53aSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*0250c53aSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*0250c53aSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*0250c53aSRobert Mustacchi  */
11*0250c53aSRobert Mustacchi 
12*0250c53aSRobert Mustacchi /*
13*0250c53aSRobert Mustacchi  * Copyright 2024 Oxide Computer Company
14*0250c53aSRobert Mustacchi  */
15*0250c53aSRobert Mustacchi 
16*0250c53aSRobert Mustacchi /*
17*0250c53aSRobert Mustacchi  * Verify that our file descriptors starting after stderr are correct based upon
18*0250c53aSRobert Mustacchi  * the series of passed in arguments from the 'oclo' program. Arguments are
19*0250c53aSRobert Mustacchi  * passed as a string that represents the flags that were originally verified
20*0250c53aSRobert Mustacchi  * pre-fork/exec via fcntl(F_GETFD). In addition, anything that was originally
21*0250c53aSRobert Mustacchi  * closed because it had FD_CLOFORK set was reopened with the same flags so we
22*0250c53aSRobert Mustacchi  * can verify that things with only FD_CLOFORK survive exec.
23*0250c53aSRobert Mustacchi  */
24*0250c53aSRobert Mustacchi 
25*0250c53aSRobert Mustacchi #include <err.h>
26*0250c53aSRobert Mustacchi #include <stdlib.h>
27*0250c53aSRobert Mustacchi #include <unistd.h>
28*0250c53aSRobert Mustacchi #include <fcntl.h>
29*0250c53aSRobert Mustacchi #include <stdbool.h>
30*0250c53aSRobert Mustacchi #include <errno.h>
31*0250c53aSRobert Mustacchi #include <string.h>
32*0250c53aSRobert Mustacchi 
33*0250c53aSRobert Mustacchi static int
verify_fdwalk_cb(void * arg,int fd)34*0250c53aSRobert Mustacchi verify_fdwalk_cb(void *arg, int fd)
35*0250c53aSRobert Mustacchi {
36*0250c53aSRobert Mustacchi 	int *max = arg;
37*0250c53aSRobert Mustacchi 	*max = fd;
38*0250c53aSRobert Mustacchi 	return (0);
39*0250c53aSRobert Mustacchi }
40*0250c53aSRobert Mustacchi 
41*0250c53aSRobert Mustacchi static bool
verify_flags(int fd,int exp_flags)42*0250c53aSRobert Mustacchi verify_flags(int fd, int exp_flags)
43*0250c53aSRobert Mustacchi {
44*0250c53aSRobert Mustacchi 	bool fail = (exp_flags & FD_CLOEXEC) != 0;
45*0250c53aSRobert Mustacchi 	int flags = fcntl(fd, F_GETFD, NULL);
46*0250c53aSRobert Mustacchi 
47*0250c53aSRobert Mustacchi 	if (flags < 0) {
48*0250c53aSRobert Mustacchi 		int e = errno;
49*0250c53aSRobert Mustacchi 
50*0250c53aSRobert Mustacchi 		if (fail) {
51*0250c53aSRobert Mustacchi 			if (e == EBADF) {
52*0250c53aSRobert Mustacchi 				(void) printf("TEST PASSED: post-exec fd %d: "
53*0250c53aSRobert Mustacchi 				    "flags 0x%x: correctly closed\n", fd,
54*0250c53aSRobert Mustacchi 				    exp_flags);
55*0250c53aSRobert Mustacchi 				return (true);
56*0250c53aSRobert Mustacchi 			}
57*0250c53aSRobert Mustacchi 
58*0250c53aSRobert Mustacchi 
59*0250c53aSRobert Mustacchi 			warn("TEST FAILED: post-fork fd %d: expected fcntl to "
60*0250c53aSRobert Mustacchi 			    "fail with EBADF, but found %s", fd,
61*0250c53aSRobert Mustacchi 			    strerrorname_np(e));
62*0250c53aSRobert Mustacchi 			return (false);
63*0250c53aSRobert Mustacchi 		}
64*0250c53aSRobert Mustacchi 
65*0250c53aSRobert Mustacchi 		warnx("TEST FAILED: post-fork fd %d: fcntl(F_GETFD) "
66*0250c53aSRobert Mustacchi 		    "unexpectedly failed with %s, expected flags %d", fd,
67*0250c53aSRobert Mustacchi 		    strerrorname_np(e), exp_flags);
68*0250c53aSRobert Mustacchi 		return (false);
69*0250c53aSRobert Mustacchi 	}
70*0250c53aSRobert Mustacchi 
71*0250c53aSRobert Mustacchi 	if (fail) {
72*0250c53aSRobert Mustacchi 		warnx("TEST FAILED: post-fork fd %d: received flags %d, but "
73*0250c53aSRobert Mustacchi 		    "expected to fail based on flags %d", fd, flags, exp_flags);
74*0250c53aSRobert Mustacchi 		return (false);
75*0250c53aSRobert Mustacchi 	}
76*0250c53aSRobert Mustacchi 
77*0250c53aSRobert Mustacchi 	if (flags != exp_flags) {
78*0250c53aSRobert Mustacchi 		warnx("TEST FAILED: post-exec fd %d: discovered flags 0x%x do "
79*0250c53aSRobert Mustacchi 		    "not match expected flags 0x%x", fd, flags, exp_flags);
80*0250c53aSRobert Mustacchi 		return (false);
81*0250c53aSRobert Mustacchi 	}
82*0250c53aSRobert Mustacchi 
83*0250c53aSRobert Mustacchi 	(void) printf("TEST PASSED: post-exec fd %d: flags 0x%x: successfully "
84*0250c53aSRobert Mustacchi 	    "matched\n", fd, exp_flags);
85*0250c53aSRobert Mustacchi 	return (true);
86*0250c53aSRobert Mustacchi }
87*0250c53aSRobert Mustacchi 
88*0250c53aSRobert Mustacchi int
main(int argc,char * argv[])89*0250c53aSRobert Mustacchi main(int argc, char *argv[])
90*0250c53aSRobert Mustacchi {
91*0250c53aSRobert Mustacchi 	int maxfd = STDIN_FILENO;
92*0250c53aSRobert Mustacchi 	int ret = EXIT_SUCCESS;
93*0250c53aSRobert Mustacchi 
94*0250c53aSRobert Mustacchi 	/*
95*0250c53aSRobert Mustacchi 	 * We should have one argument for each fd we found, ignoring stdin,
96*0250c53aSRobert Mustacchi 	 * stdout, and stderr. argc will also have an additional entry for our
97*0250c53aSRobert Mustacchi 	 * program name, which we want to skip. Note, the last fd may not exist
98*0250c53aSRobert Mustacchi 	 * because it was marked for close, hence the use of '>' below.
99*0250c53aSRobert Mustacchi 	 */
100*0250c53aSRobert Mustacchi 	(void) fdwalk(verify_fdwalk_cb, &maxfd);
101*0250c53aSRobert Mustacchi 	if (maxfd - 3 > argc - 1) {
102*0250c53aSRobert Mustacchi 		errx(EXIT_FAILURE, "TEST FAILED: found more fds %d than "
103*0250c53aSRobert Mustacchi 		    "arguments %d", maxfd - 3, argc - 1);
104*0250c53aSRobert Mustacchi 	}
105*0250c53aSRobert Mustacchi 
106*0250c53aSRobert Mustacchi 	for (int i = 1; i < argc; i++) {
107*0250c53aSRobert Mustacchi 		const char *errstr;
108*0250c53aSRobert Mustacchi 		int targ_fd = i + STDERR_FILENO;
109*0250c53aSRobert Mustacchi 		long long targ_flags = strtonumx(argv[i], 0,
110*0250c53aSRobert Mustacchi 		    FD_CLOEXEC | FD_CLOFORK, &errstr, 0);
111*0250c53aSRobert Mustacchi 
112*0250c53aSRobert Mustacchi 		if (errstr != NULL) {
113*0250c53aSRobert Mustacchi 			errx(EXIT_FAILURE, "TEST FAILED: failed to parse "
114*0250c53aSRobert Mustacchi 			    "argument %d: %s is %s", i, argv[i], errstr);
115*0250c53aSRobert Mustacchi 		}
116*0250c53aSRobert Mustacchi 
117*0250c53aSRobert Mustacchi 		if (!verify_flags(targ_fd, (int)targ_flags))
118*0250c53aSRobert Mustacchi 			ret = EXIT_FAILURE;
119*0250c53aSRobert Mustacchi 	}
120*0250c53aSRobert Mustacchi 
121*0250c53aSRobert Mustacchi 	return (ret);
122*0250c53aSRobert Mustacchi }
123