The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=4140012f83690e9ed9b31d87c16e4f698332e24c
commit 4140012f83690e9ed9b31d87c16e4f698332e24c Author: Ricardo Branco <rbra...@suse.de> AuthorDate: 2025-06-16 17:45:54 +0000 Commit: Mark Johnston <ma...@freebsd.org> CommitDate: 2025-07-06 23:09:10 +0000 tests: Adapt oclo tests to FreeBSD MFC after: 1 month Pull Request: https://github.com/freebsd/freebsd-src/pull/1698 --- .../opensolaris/tests/os-tests/tests/oclo/oclo.c | 91 +++++++++++++++------- .../tests/os-tests/tests/oclo/oclo_errors.c | 25 ++++-- .../tests/os-tests/tests/oclo/ocloexec_verify.c | 47 +++++++---- tests/Makefile | 5 ++ tests/oclo/Makefile | 11 +++ 5 files changed, 126 insertions(+), 53 deletions(-) diff --git a/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo.c b/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo.c index b21c253fca24..8e6f7c726f24 100644 --- a/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo.c +++ b/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo.c @@ -45,21 +45,54 @@ * with the divergence of other implementations. */ -#include <stdlib.h> -#include <unistd.h> -#include <stdbool.h> -#include <err.h> -#include <sys/types.h> +#include <sys/param.h> +#include <sys/sysctl.h> #include <sys/stat.h> -#include <fcntl.h> -#include <sys/sysmacros.h> -#include <sys/fork.h> -#include <wait.h> +#include <sys/wait.h> + +#include <netinet/in.h> +#include <sys/socket.h> + +#include <err.h> #include <errno.h> -#include <string.h> -#include <limits.h> +#include <fcntl.h> #include <libgen.h> -#include <sys/socket.h> +#include <limits.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +void *recallocarray(void *, size_t, size_t, size_t); + +#define strerrorname_np(e) (sys_errlist[e]) + +/* + * Get pathname to avoid reading /proc/curproc/exe + * + * Taken from procstat_getpathname_sysctl() + */ +static int +getpathname(pid_t pid, char *pathname, size_t maxlen) +{ + int error, name[4]; + size_t len; + + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = KERN_PROC_PATHNAME; + name[3] = pid; + len = maxlen; + error = sysctl(name, nitems(name), pathname, &len, NULL, 0); + if (error != 0 && errno != ESRCH) + warn("sysctl: kern.proc.pathname: %d", pid); + if (len == 0) + pathname[0] = '\0'; + return (error); +} /* * Verification program name. @@ -93,8 +126,8 @@ typedef struct clo_rtdata { } clo_rtdata_t; static clo_rtdata_t *oclo_rtdata; -size_t oclo_rtdata_nents = 0; -size_t oclo_rtdata_next = 0; +static size_t oclo_rtdata_nents = 0; +static size_t oclo_rtdata_next = 0; static int oclo_nextfd = STDERR_FILENO + 1; static bool @@ -267,11 +300,13 @@ oclo_fdup_common(const clo_create_t *c, int targ_flags, int cmd) break; case F_DUP2FD: case F_DUP2FD_CLOEXEC: +#ifdef F_DUP2FD_CLOFORK case F_DUP2FD_CLOFORK: +#endif dup = fcntl(fd, cmd, fd + 1); break; case F_DUP3FD: - dup = fcntl(fd, cmd, fd + 1, targ_flags); + dup = fcntl(fd, cmd | (targ_flags << F_DUP3FD_SHIFT), fd + 1); break; default: errx(EXIT_FAILURE, "TEST FAILURE: %s: internal error: " @@ -310,11 +345,13 @@ oclo_fdup2fd(const clo_create_t *c) oclo_fdup_common(c, 0, F_DUP2FD); } +#ifdef F_DUP2FD_CLOFORK static void oclo_fdup2fd_fork(const clo_create_t *c) { oclo_fdup_common(c, FD_CLOFORK, F_DUP2FD_CLOFORK); } +#endif static void oclo_fdup2fd_exec(const clo_create_t *c) @@ -604,7 +641,7 @@ oclo_rights_common(const clo_create_t *c, int targ_flags) if (msg.msg_controllen < CMSG_SPACE(sizeof (int))) { errx(EXIT_FAILURE, "TEST FAILED: %s: found insufficient " - "message control length: expected at least 0x%x, found " + "message control length: expected at least 0x%zx, found " "0x%x", c->clo_desc, CMSG_SPACE(sizeof (int)), msg.msg_controllen); } @@ -795,6 +832,7 @@ static const clo_create_t oclo_create[] = { { .clo_flags = FD_CLOEXEC | FD_CLOFORK, .clo_func = oclo_fdup2fd }, { +#ifdef F_DUP2FD_CLOFORK .clo_desc = "fcntl(F_DUP2FD_CLOFORK) none", .clo_flags = 0, .clo_func = oclo_fdup2fd_fork @@ -811,6 +849,7 @@ static const clo_create_t oclo_create[] = { { .clo_flags = FD_CLOEXEC | FD_CLOFORK, .clo_func = oclo_fdup2fd_fork }, { +#endif .clo_desc = "fcntl(F_DUP2FD_CLOEXEC) none", .clo_flags = 0, .clo_func = oclo_fdup2fd_exec @@ -1216,20 +1255,12 @@ oclo_exec(void) char dir[PATH_MAX], file[PATH_MAX]; char **argv; - ret = readlink("/proc/self/path/a.out", dir, sizeof (dir)); - if (ret < 0) { - err(EXIT_FAILURE, "TEST FAILED: failed to read our a.out path " - "from /proc"); - } else if (ret == 0) { - errx(EXIT_FAILURE, "TEST FAILED: reading /proc/self/path/a.out " - "returned 0 bytes"); - } else if (ret == sizeof (dir)) { - errx(EXIT_FAILURE, "TEST FAILED: Using /proc/self/path/a.out " - "requires truncation"); - } + ret = getpathname(getpid(), dir, sizeof(dir)); + if (ret < 0) + err(EXIT_FAILURE, "TEST FAILED: failed to read executable path"); if (snprintf(file, sizeof (file), "%s/%s", dirname(dir), OCLO_VERIFY) >= - sizeof (file)) { + (int)sizeof (file)) { errx(EXIT_FAILURE, "TEST FAILED: cannot assemble exec path " "name: internal buffer overflow"); } @@ -1270,11 +1301,11 @@ main(void) * Treat failure during this set up phase as a hard failure. There's no * reason to continue if we can't successfully create the FDs we expect. */ - for (size_t i = 0; i < ARRAY_SIZE(oclo_create); i++) { + for (size_t i = 0; i < nitems(oclo_create); i++) { oclo_create[i].clo_func(&oclo_create[i]); } - pid_t child = forkx(FORK_NOSIGCHLD | FORK_WAITPID); + pid_t child = fork(); if (child == 0) { if (!oclo_verify_fork()) { ret = EXIT_FAILURE; diff --git a/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo_errors.c b/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo_errors.c index 9d9841271856..05b0c1a0839b 100644 --- a/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo_errors.c +++ b/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/oclo_errors.c @@ -24,16 +24,21 @@ * o accept4() */ -#include <stdlib.h> +#include <netinet/in.h> +#include <sys/socket.h> + #include <err.h> -#include <stdio.h> -#include <unistd.h> -#include <sys/stdbool.h> #include <errno.h> -#include <string.h> #include <fcntl.h> #include <limits.h> -#include <sys/socket.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define strerrorname_np(e) (sys_errlist[e]) static bool oclo_check(const char *desc, const char *act, int ret, int e) @@ -42,7 +47,7 @@ oclo_check(const char *desc, const char *act, int ret, int e) warnx("TEST FAILED: %s: fd was %s!", desc, act); return (false); } else if (errno != EINVAL) { - int e = errno; + e = errno; warnx("TEST FAILED: %s: failed with %s, expected " "EINVAL", desc, strerrorname_np(e)); return (false); @@ -63,7 +68,7 @@ oclo_dup3(const char *desc, int flags) static bool oclo_dup3fd(const char *desc, int flags) { - int fd = fcntl(STDERR_FILENO, F_DUP3FD, 23, flags); + int fd = fcntl(STDERR_FILENO, F_DUP3FD | (flags << F_DUP3FD_SHIFT), 23); return (oclo_check(desc, "duplicated", fd, errno)); } @@ -77,12 +82,14 @@ oclo_pipe2(const char *desc, int flags) return (oclo_check(desc, "piped", ret, errno)); } +#if 0 static bool oclo_socket(const char *desc, int type) { int fd = socket(PF_UNIX, SOCK_STREAM | type, 0); return (oclo_check(desc, "created", fd, errno)); } +#endif static bool oclo_accept(const char *desc, int flags) @@ -169,6 +176,7 @@ main(void) ret = EXIT_FAILURE; } +#if 0 /* These tests are known to fail on FreeBSD */ if (!oclo_socket("socket(): INT32_MAX", INT32_MAX)) { ret = EXIT_FAILURE; } @@ -176,6 +184,7 @@ main(void) if (!oclo_socket("socket(): 3 << 25", 3 << 25)) { ret = EXIT_FAILURE; } +#endif if (!oclo_accept("accept4(): INT32_MAX", INT32_MAX)) { ret = EXIT_FAILURE; diff --git a/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/ocloexec_verify.c b/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/ocloexec_verify.c index ea8ad0e058b1..e33c61f03d54 100644 --- a/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/ocloexec_verify.c +++ b/cddl/contrib/opensolaris/tests/os-tests/tests/oclo/ocloexec_verify.c @@ -23,20 +23,36 @@ * properly cleared. */ +#include <sys/types.h> +#include <sys/user.h> #include <err.h> -#include <stdlib.h> -#include <unistd.h> +#include <errno.h> #include <fcntl.h> +#include <libutil.h> #include <stdbool.h> -#include <errno.h> +#include <stdio.h> +#include <stdlib.h> #include <string.h> +#include <unistd.h> + +#define strerrorname_np(e) (sys_errlist[e]) static int -verify_fdwalk_cb(void *arg, int fd) +getmaxfd(void) { - int *max = arg; - *max = fd; - return (0); + struct kinfo_file *files; + int i, cnt, max; + + if ((files = kinfo_getfile(getpid(), &cnt)) == NULL) + err(1, "kinfo_getfile"); + + max = -1; + for (i = 0; i < cnt; i++) + if (files[i].kf_fd > max) + max = files[i].kf_fd; + + free(files); + return (max); } /* @@ -103,7 +119,7 @@ verify_flags(int fd, int exp_flags) int main(int argc, char *argv[]) { - int maxfd = STDIN_FILENO; + int maxfd; int ret = EXIT_SUCCESS; /* @@ -112,24 +128,25 @@ main(int argc, char *argv[]) * program name, which we want to skip. Note, the last fd may not exist * because it was marked for close, hence the use of '>' below. */ - (void) fdwalk(verify_fdwalk_cb, &maxfd); + maxfd = getmaxfd(); if (maxfd - 3 > argc - 1) { errx(EXIT_FAILURE, "TEST FAILED: found more fds %d than " "arguments %d", maxfd - 3, argc - 1); } for (int i = 1; i < argc; i++) { - const char *errstr; + char *endptr; int targ_fd = i + STDERR_FILENO; - long long targ_flags = strtonumx(argv[i], 0, - FD_CLOEXEC | FD_CLOFORK, &errstr, 0); + errno = 0; + long long val = strtoll(argv[i], &endptr, 0); - if (errstr != NULL) { + if (errno != 0 || *endptr != '\0' || + (val < 0 || val > (FD_CLOEXEC | FD_CLOFORK))) { errx(EXIT_FAILURE, "TEST FAILED: failed to parse " - "argument %d: %s is %s", i, argv[i], errstr); + "argument %d: %s", i, argv[i]); } - if (!verify_flags(targ_fd, (int)targ_flags)) + if (!verify_flags(targ_fd, (int)val)) ret = EXIT_FAILURE; } diff --git a/tests/Makefile b/tests/Makefile index e8dd7793f169..451d55498a26 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,3 +1,5 @@ +.include <src.opts.mk> + PACKAGE= tests TESTSDIR= ${TESTSBASE} @@ -11,6 +13,9 @@ SUBDIR+= examples SUBDIR+= include SUBDIR+= sys SUBDIR+= atf_python +.if ${MK_CDDL} != "no" +SUBDIR+= oclo +.endif SUBDIR_PARALLEL= diff --git a/tests/oclo/Makefile b/tests/oclo/Makefile new file mode 100644 index 000000000000..350c9f857c85 --- /dev/null +++ b/tests/oclo/Makefile @@ -0,0 +1,11 @@ +.PATH: ${SRCTOP}/cddl/contrib/opensolaris/tests/os-tests/tests/oclo + +TESTSDIR= ${TESTSBASE}/cddl/oclo + +PLAIN_TESTS_C= oclo oclo_errors ocloexec_verify + +SRCS.oclo= oclo.c +LIBADD.oclo+= openbsd +LIBADD.ocloexec_verify+= util + +.include <bsd.test.mk>