Import more NetBSD system call regression tests.
authormbuhl <mbuhl@openbsd.org>
Thu, 2 Sep 2021 12:40:44 +0000 (12:40 +0000)
committermbuhl <mbuhl@openbsd.org>
Thu, 2 Sep 2021 12:40:44 +0000 (12:40 +0000)
OK bluhm@

17 files changed:
regress/lib/libc/sys/Makefile
regress/lib/libc/sys/README
regress/lib/libc/sys/atf-c.h
regress/lib/libc/sys/h_macros.h
regress/lib/libc/sys/macros.h
regress/lib/libc/sys/t_clock_gettime.c
regress/lib/libc/sys/t_connect.c [new file with mode: 0644]
regress/lib/libc/sys/t_fork.c [new file with mode: 0644]
regress/lib/libc/sys/t_kevent.c [new file with mode: 0644]
regress/lib/libc/sys/t_minherit.c [new file with mode: 0644]
regress/lib/libc/sys/t_pollts.c [new file with mode: 0644]
regress/lib/libc/sys/t_ppoll.c [new file with mode: 0644]
regress/lib/libc/sys/t_setrlimit.c [new file with mode: 0644]
regress/lib/libc/sys/t_sigaltstack.c [new file with mode: 0644]
regress/lib/libc/sys/t_syscall.c
regress/lib/libc/sys/t_wait_noproc.c [new file with mode: 0644]
regress/lib/libc/sys/t_wait_noproc_wnohang.c [new file with mode: 0644]

index 7a3b920..acb5c89 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile,v 1.10 2020/12/17 00:51:11 bluhm Exp $
+#      $OpenBSD: Makefile,v 1.11 2021/09/02 12:40:44 mbuhl Exp $
 
 # Copyright (c) 2019 Moritz Buhl <openbsd@moritzbuhl.de>
 # Copyright (c) 2019 Alexander Bluhm <bluhm@openbsd.org>
@@ -29,20 +29,45 @@ PROGS =
 PROGS +=       t_access
 PROGS +=       t_bind
 PROGS +=       t_chroot t_clock_gettime
+PROGS +=       t_connect
 PROGS +=       t_dup
+PROGS +=       t_fork
 PROGS +=       t_fsync
 PROGS +=       t_getgroups t_getitimer t_getlogin t_getpid t_getrusage
 PROGS +=       t_getsid t_getsockname t_gettimeofday
+PROGS +=       t_kevent
 PROGS +=       t_kill
 PROGS +=       t_link t_listen
-PROGS +=       t_mkdir t_mkfifo t_mknod t_mlock t_mmap
-PROGS +=       t_msgctl t_msgget t_msgrcv t_msgsnd t_msync
-PROGS +=       t_pipe t_pipe2 t_poll t_ptrace
+PROGS +=       t_minherit
+PROGS +=       t_mkdir
+PROGS +=       t_mkfifo
+PROGS +=       t_mknod
+PROGS +=       t_mlock
+PROGS +=       t_mmap
+PROGS +=       t_msgctl
+PROGS +=       t_msgget
+PROGS +=       t_msgrcv
+PROGS +=       t_msgsnd
+PROGS +=       t_msync
+PROGS +=       t_pipe
+PROGS +=       t_pipe2
+PROGS +=       t_poll
+PROGS +=       t_ppoll
+PROGS +=       t_ptrace
 PROGS +=       t_revoke
-PROGS +=       t_select t_sendrecv t_setuid t_socketpair t_sigaction t_stat
+PROGS +=       t_select
+PROGS +=       t_sendrecv
+PROGS +=       t_setrlimit
+PROGS +=       t_setuid
+PROGS +=       t_sigaction
+PROGS +=       t_sigaltstack
+PROGS +=       t_socketpair
+PROGS +=       t_stat
 PROGS +=       t_syscall
 PROGS +=       t_truncate
 PROGS +=       t_umask t_unlink
+PROGS +=       t_wait_noproc
+PROGS +=       t_wait_noproc_wnohang
 PROGS +=       t_write
 
 # failing tests
index 0f7d82e..5606fca 100644 (file)
@@ -3,24 +3,33 @@ Regression tests for system calls ported from NetBSD.
 Reimplement ATF with many hacks to adjust the tests as little as possible.
 
 Tests passing without source file adjustments:
-t_access       t_getpid        t_link          t_msgsnd        t_sigaction
-t_bind         t_getsid        t_listen        t_msync         t_socketpair
-t_getgroups    t_getsockname   t_mkdir         t_pipe          t_truncate
-t_getitimer    t_gettimeofday  t_mkfifo        t_sendrecv      t_umask
-t_getlogin     t_kill          t_msgctl        t_setuid        t_write
+t_access       t_getsockname   t_msgctl        t_sigaltstack
+t_bind         t_gettimeofday  t_msgsnd        t_socketpair
+t_conect       t_kill          t_msync         t_truncate
+t_getgroups    t_link          t_pipe          t_umask
+t_getitimer    t_listen        t_ppoll         t_write
+t_getlogin     t_minherit      t_sendrecv
+t_getpid       t_mkdir         t_setuid
+t_getsid       t_mkfifo        t_sigaction
 
 Tests passing after adjustments:
-t_chroot       - fchroot is not implemented
-t_clock_gettime        - requires sysctlbyname
-t_dup          - OpenBSD dup3 is similar to Linux dup3
-t_fsync                - replace mkstemp
-t_getrusage    - no expected fail, PR kern/30115 is NetBSD, work more
-t_mknod        - remove tests for unsupported file types
-t_msgget       - remove msgget_limit test
-t_poll                 - remove pollts_* tests
-t_ptrace       - change EPERM -> EINVAL for PT_ATTACH of a parent
-t_revoke       - remove basic tests, revoke only on ttys supported
-t_select       - remove sigset_t struct as it is int on OpenBSD
+t_chroot               - fchroot is not implemented
+t_clock_gettime                - requires sysctlbyname
+t_dup                  - OpenBSD dup3 is similar to Linux dup3
+t_fork                 - add reallocarr function, remove clone(2) tests
+t_fsync                        - replace mkstemp
+t_getrusage            - no expected fail, PR kern/30115 is NetBSD, work more
+t_kevent               - no EVFILT_USER, DRVCTLDEV, passing kqueue forbidden
+t_mknod                - remove tests for unsupported file types
+t_msgget               - remove msgget_limit test
+t_poll                         - remove pollts_* tests
+t_ptrace               - change EPERM -> EINVAL for PT_ATTACH of a parent
+t_revoke               - remove basic tests, revoke only on ttys supported
+t_select               - remove sigset_t struct as it is int on OpenBSD
+t_setrlimit            - remove unsupported resource parameters and lwp
+t_syscall              - add __syscall prototype
+t_wait_noproc          - waitid and wait6 are not implemented
+t_wait_noproc_wnohang  - waitid and wait6 are not implemented
 
 Failing tests:
 t_mlock                - wrong errno, succeeds where not expected, POSIX imprecise
@@ -28,40 +37,37 @@ t_mmap              - ENOTBLK on test NetBSD is skipping, remove mmap_va0 test
 t_msgrcv       - msgrcv(id, &r, 3 - 1, 0x41, 004000) != -1
 t_pipe2        - closefrom(4) == -1, remove F_GETNOSIGPIPE and nosigpipe test
 t_stat                 - invalid GID with doas
-t_syscall      - SIGSEGV
 t_unlink       - wrong errno according to POSIX
+t_vfork                - !(((status) & 0177) == 0) evaluated to false, SIGSTOP wrong
 
 Excluded tests:
 t_clock_nanosleep      - not available
 t_clone                        - not available
-t_connect              -
-t_fork                 -
-t_getcontext           -
-t_issetugid            -
-t_kevent               -
+t_futex_ops            - no lwp
+t_futex_robust         - no lwp
+t_getcontext           - not available, removed in POSIX.1-2008
+t_getrandom            - not available
+t_issetugid            - works as iplemented
 t_lwp_create           - not available
 t_lwp_ctl              - not available
 t_mincore              - removed
-t_minherit             -
-t_mprotect             -
+t_mprotect             - no exec_prot_support and no return_one in libc
 t_nanosleep            - not available
-t_posix_fadvise                -
-t_posix_fallocate      -
+t_pollts               - not available
+t_posix_fadvise                - optional POSIX Advisory Information
+t_posix_fallocate      - optional POSIX Advisory Information
+t_ptrace_sigchld       -
 t_ptrace_wait          -
 t_ptrace_wait3         -
 t_ptrace_wait4         -
 t_ptrace_wait6         - not implemented
 t_ptrace_waitid                -
 t_ptrace_waitpid       -
-t_recvmmsg             -
-t_sendmmsg             -
-t_setrlimit            -
-t_sigqueue             -
-t_sigtimedwait         -
-t_swapcontext          -
-t_timer_create         -
-t_ucontext             -
-t_vfork                        -
-t_wait                 -
-t_wait_noproc          -
-t_wait_noproc_wnohang  -
+t_recvmmsg             - not implemented, not POSIX
+t_sendmmsg             - not implemented, not POSIX
+t_sigqueue             - not implemented, added in POSIX.1-2004
+t_sigtimedwait         - not implemented, added in POSIX.1-2004
+t_swapcontext          - not available, removed in POSIX.1-2008
+t_timer_create         - not implemented, added in POSIX.1-2004
+t_ucontext             - not available, removed in POSIX.1-2008
+t_wait                 - wait6 is not available, not POSIX
index 93e2026..c10628b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: atf-c.h,v 1.2 2021/06/09 19:42:46 mortimer Exp $      */
+/*     $OpenBSD: atf-c.h,v 1.3 2021/09/02 12:40:44 mbuhl Exp $ */
 /*
  * Copyright (c) 2019 Moritz Buhl <openbsd@moritzbuhl.de>
  *
@@ -76,6 +76,7 @@ ATF_TC_FUNCTIONS(fn)
 #define ATF_CHECK              ATF_REQUIRE
 #define ATF_CHECK_MSG          ATF_REQUIRE_MSG
 #define ATF_CHECK_EQ           ATF_REQUIRE_EQ
+#define ATF_CHECK_ERRNO                ATF_REQUIRE_ERRNO
 #define ATF_CHECK_STREQ        ATF_REQUIRE_STREQ
 
 #define atf_req(exp, err, msg, ...)                                    \
index 227db0f..22f7ed8 100644 (file)
@@ -1,3 +1,4 @@
+/*     $OpenBSD: h_macros.h,v 1.2 2021/09/02 12:40:44 mbuhl Exp $      */
 /* $NetBSD: h_macros.h,v 1.13 2016/08/20 15:49:08 christos Exp $ */
 
 /*-
index ef858d1..56f9ff1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: macros.h,v 1.2 2020/01/30 08:22:30 mpi Exp $  */
+/*     $OpenBSD: macros.h,v 1.3 2021/09/02 12:40:44 mbuhl Exp $        */
 /* Public domain - Moritz Buhl */
 
 #include <sys/param.h>
@@ -49,6 +49,14 @@ sysctlbyname(char* s, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
         return sysctl(mib, miblen, oldp, oldlenp, newp, newlen);
 }
 
+/* t_connect.c */
+#define IPPORT_RESERVEDMAX     1023
+
+/* t_fork.c */
+#define kinfo_proc2    kinfo_proc
+#define KERN_PROC2     KERN_PROC
+#define reallocarr(pp, n, s)   ((*pp = reallocarray(*pp, n, s)), *pp == NULL)
+
 /* t_mlock.c */
 #define MAP_WIRED      __MAP_NOREPLACE
 
@@ -63,3 +71,7 @@ sysctlbyname(char* s, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
 
 /* t_write.c */
 #define _PATH_DEVZERO  "/dev/zero"
+
+/* t_wait_noproc.c */
+#define ___STRING(x)   #x
+#define __BIT(n)       (1 << (n))
index 2067107..b75be63 100644 (file)
@@ -1,3 +1,4 @@
+/*     $OpenBSD: t_clock_gettime.c,v 1.2 2021/09/02 12:40:44 mbuhl Exp $       */
 /* $NetBSD: t_clock_gettime.c,v 1.3 2017/01/13 21:30:41 christos Exp $ */
 
 /*-
diff --git a/regress/lib/libc/sys/t_connect.c b/regress/lib/libc/sys/t_connect.c
new file mode 100644 (file)
index 0000000..c1730a4
--- /dev/null
@@ -0,0 +1,135 @@
+/*     $OpenBSD: t_connect.c,v 1.1 2021/09/02 12:40:44 mbuhl Exp $     */
+/*     $NetBSD: t_connect.c,v 1.3 2017/01/13 20:09:48 christos Exp $   */
+/*
+ * Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "macros.h"
+
+#include <sys/socket.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "atf-c.h"
+
+ATF_TC(connect_low_port);
+ATF_TC_HEAD(connect_low_port, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Checks that low-port allocation "
+           "works");
+       atf_tc_set_md_var(tc, "require.user", "root");
+}
+ATF_TC_BODY(connect_low_port, tc)
+{
+       struct sockaddr_in sin, sinlist;
+       int sd, val, slist;
+       socklen_t slen;
+
+       slist = socket(AF_INET, SOCK_STREAM, 0);
+       sd = socket(AF_INET, SOCK_STREAM, 0);
+
+       ATF_REQUIRE(sd > 0);
+       ATF_REQUIRE(slist > 0);
+
+       /* bind listening socket */
+       memset(&sinlist, 0, sizeof(sinlist));
+       sinlist.sin_family = AF_INET;
+       sinlist.sin_port = htons(31522);
+       sinlist.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+       ATF_REQUIRE_EQ(bind(slist,
+           (struct sockaddr *)&sinlist, sizeof(sinlist)), 0);
+       ATF_REQUIRE_EQ(listen(slist, 1), 0);
+
+       val = IP_PORTRANGE_LOW;
+       if (setsockopt(sd, IPPROTO_IP, IP_PORTRANGE, &val,
+           sizeof(val)) == -1)
+               atf_tc_fail("setsockopt failed: %s", strerror(errno));
+
+       memset(&sin, 0, sizeof(sin));
+
+       sin.sin_port = htons(31522);
+       sin.sin_addr.s_addr = inet_addr("127.0.0.1");
+       sin.sin_family = AF_INET;
+
+       if (connect(sd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
+               int serrno = errno;
+               atf_tc_fail("connect failed: %s%s",
+                   strerror(serrno),
+                   serrno != EACCES ? "" :
+                   " (see http://mail-index.netbsd.org/"
+                   "source-changes/2007/12/16/0011.html)");
+       }
+
+       slen = sizeof(sin);
+       ATF_REQUIRE_EQ(getsockname(sd, (struct sockaddr *)&sin, &slen), 0);
+       ATF_REQUIRE_EQ(slen, sizeof(sin));
+       ATF_REQUIRE(ntohs(sin.sin_port) <= IPPORT_RESERVEDMAX);
+
+       close(sd);
+       close(slist);
+}
+
+ATF_TC(connect_foreign_family);
+ATF_TC_HEAD(connect_foreign_family, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Checks that connecting a socket "
+           "with a different address family fails");
+}
+ATF_TC_BODY(connect_foreign_family, tc)
+{
+       struct sockaddr_in addr;
+
+       /* addr.sin_family = AF_UNSPEC = 0 */
+       memset(&addr, 0, sizeof(addr));
+
+       /*
+        * it is not necessary to initialize sin_{addr,port} since
+        * those structure members shall not be accessed if connect
+        * fails correctly.
+        */
+
+       int sock = socket(AF_LOCAL, SOCK_STREAM, 0);
+       ATF_REQUIRE(sock != -1);
+
+       ATF_REQUIRE(-1 == connect(sock, (struct sockaddr *)&addr, sizeof(addr)));
+       ATF_REQUIRE(EAFNOSUPPORT == errno);
+
+       close(sock);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+       ATF_TP_ADD_TC(tp, connect_low_port);
+       ATF_TP_ADD_TC(tp, connect_foreign_family);
+
+       return atf_no_error();
+}
diff --git a/regress/lib/libc/sys/t_fork.c b/regress/lib/libc/sys/t_fork.c
new file mode 100644 (file)
index 0000000..76d66ce
--- /dev/null
@@ -0,0 +1,387 @@
+/*     $OpenBSD: t_fork.c,v 1.1 2021/09/02 12:40:44 mbuhl Exp $        */
+/*     $NetBSD: t_fork.c,v 1.4 2019/04/06 15:41:54 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2018, 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "macros.h"
+
+#include <sys/cdefs.h>
+__COPYRIGHT("@(#) Copyright (c) 2018, 2019\
+ The NetBSD Foundation, inc. All rights reserved.");
+__RCSID("$NetBSD: t_fork.c,v 1.4 2019/04/06 15:41:54 kamil Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "atf-c.h"
+
+#ifdef VFORK
+#define FORK vfork
+#else
+#define FORK fork
+#endif
+
+/*
+ * A child process cannot call atf functions and expect them to magically
+ * work like in the parent.
+ * The printf(3) messaging from a child will not work out of the box as well
+ * without estabilishing a communication protocol with its parent. To not
+ * overcomplicate the tests - do not log from a child and use err(3)/errx(3)
+ * wrapped with ASSERT_EQ()/ASSERT_NEQ() as that is guaranteed to work.
+ */
+#define ASSERT_EQ(x, y)                                                                \
+do {                                                                           \
+       uintmax_t vx = (x);                                                     \
+       uintmax_t vy = (y);                                                     \
+       int ret = vx == vy;                                                     \
+       if (!ret)                                                               \
+               errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: "         \
+                   "%s(%ju) == %s(%ju)", __FILE__, __LINE__, __func__,         \
+                   #x, vx, #y, vy);                                            \
+} while (/*CONSTCOND*/0)
+
+#define ASSERT_NEQ(x, y)                                                       \
+do {                                                                           \
+       uintmax_t vx = (x);                                                     \
+       uintmax_t vy = (y);                                                     \
+       int ret = vx != vy;                                                     \
+       if (!ret)                                                               \
+               errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: "         \
+                   "%s(%ju) != %s(%ju)", __FILE__, __LINE__, __func__,         \
+                   #x, vx, #y, vy);                                            \
+} while (/*CONSTCOND*/0)
+
+static pid_t
+await_stopped_child(pid_t process)
+{
+       struct kinfo_proc2 *p = NULL;
+       size_t i, len;
+       pid_t child = -1;
+
+       int name[] = {
+               [0] = CTL_KERN,
+               [1] = KERN_PROC2,
+               [2] = KERN_PROC_ALL,
+               [3] = 0,
+               [4] = sizeof(struct kinfo_proc2),
+               [5] = 0
+       };
+
+       const size_t namelen = __arraycount(name);
+
+       /* Await the process becoming a zombie */
+       while(1) {
+               name[5] = 0;
+
+               ASSERT_EQ(sysctl(name, namelen, 0, &len, NULL, 0), 0);
+
+               ASSERT_EQ(reallocarr(&p, len, sizeof(struct kinfo_proc2)), 0);
+
+               name[5] = len;
+
+               ASSERT_EQ(sysctl(name, namelen, p, &len, NULL, 0), 0);
+
+               for (i = 0; i < len/sizeof(struct kinfo_proc2); i++) {
+                       if (p[i].p_pid == getpid())
+                               continue;
+                       if (p[i].p_ppid != process)
+                               continue;
+#ifndef __OpenBSD__
+                       if (p[i].p_stat != LSSTOP)
+                               continue;
+#endif
+                       child = p[i].p_pid;
+                       break;
+               }
+
+               if (child != -1)
+                       break;
+
+               ASSERT_EQ(usleep(1000), 0);
+       }
+
+       /* Free the buffer */
+       ASSERT_EQ(reallocarr(&p, 0, sizeof(struct kinfo_proc2)), 0);
+
+       return child;
+}
+
+static void
+raise_raw(int sig)
+{
+       int rv, status;
+       pid_t child, parent, watcher, wpid;
+       int expect_core = (sig == SIGABRT) ? 1 : 0;
+
+       /*
+        * Spawn a dedicated thread to watch for a stopped child and emit
+        * the SIGKILL signal to it.
+        *
+        * This is required in vfork(2)ing parent and optional in fork(2).
+        *
+        * vfork(2) might clobber watcher, this means that it's safer and
+        * simpler to reparent this process to initproc and forget about it.
+        */
+       if (sig == SIGSTOP
+#ifndef VFORK
+           || (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
+#endif
+           ) {
+
+               parent = getpid();
+
+               watcher = fork();
+               ATF_REQUIRE(watcher != 1);
+               if (watcher == 0) {
+                       /* Double fork(2) trick to reparent to initproc */
+                       watcher = fork();
+                       ASSERT_NEQ(watcher, -1);
+                       if (watcher != 0)
+                               _exit(0);
+
+                       child = await_stopped_child(parent);
+
+                       errno = 0;
+                       rv = kill(child, SIGKILL);
+                       ASSERT_EQ(rv, 0);
+                       ASSERT_EQ(errno, 0);
+
+                       /* This exit value will be collected by initproc */
+                       _exit(0);
+               }
+
+               wpid = waitpid(watcher, &status, 0);
+
+               ATF_REQUIRE_EQ(wpid, watcher);
+
+               ATF_REQUIRE(WIFEXITED(status));
+               ATF_REQUIRE(!WIFCONTINUED(status));
+               ATF_REQUIRE(!WIFSIGNALED(status));
+               ATF_REQUIRE(!WIFSTOPPED(status));
+               ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
+       }
+
+       child = FORK();
+       ATF_REQUIRE(child != 1);
+       if (child == 0) {
+               rv = raise(sig);
+               ASSERT_EQ(rv, 0);
+               _exit(0);
+       }
+       wpid = waitpid(child, &status, 0);
+
+       ATF_REQUIRE_EQ(wpid, child);
+
+       switch (sig) {
+       case SIGKILL:
+       case SIGABRT:
+       case SIGHUP:
+               ATF_REQUIRE(!WIFEXITED(status));
+               ATF_REQUIRE(!WIFCONTINUED(status));
+               ATF_REQUIRE(WIFSIGNALED(status));
+               ATF_REQUIRE(!WIFSTOPPED(status));
+               ATF_REQUIRE_EQ(WTERMSIG(status), sig);
+               ATF_REQUIRE_EQ(!!WCOREDUMP(status), expect_core);
+               break;
+#ifdef VFORK
+       case SIGTSTP:
+       case SIGTTIN:
+       case SIGTTOU:
+#endif
+       case SIGCONT:
+               ATF_REQUIRE(WIFEXITED(status));
+               ATF_REQUIRE(!WIFCONTINUED(status));
+               ATF_REQUIRE(!WIFSIGNALED(status));
+               ATF_REQUIRE(!WIFSTOPPED(status));
+               ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
+               break;
+#ifndef VFORK
+       case SIGTSTP:
+       case SIGTTIN:
+       case SIGTTOU:
+#endif
+       case SIGSTOP:
+               ATF_REQUIRE(!WIFEXITED(status));
+               ATF_REQUIRE(!WIFCONTINUED(status));
+               ATF_REQUIRE(WIFSIGNALED(status));
+               ATF_REQUIRE(!WIFSTOPPED(status));
+               ATF_REQUIRE_EQ(WTERMSIG(status), SIGKILL);
+               ATF_REQUIRE_EQ(!!WCOREDUMP(status), 0);
+       }
+}
+
+#define RAISE(test, sig)                                                       \
+ATF_TC(test);                                                                  \
+ATF_TC_HEAD(test, tc)                                                          \
+{                                                                              \
+                                                                               \
+       atf_tc_set_md_var(tc, "descr",                                          \
+           "raise " #sig " in a child");                                       \
+}                                                                              \
+                                                                               \
+ATF_TC_BODY(test, tc)                                                          \
+{                                                                              \
+                                                                               \
+       raise_raw(sig);                                                         \
+}
+
+RAISE(raise1, SIGKILL) /* non-maskable */
+RAISE(raise2, SIGSTOP) /* non-maskable */
+RAISE(raise3, SIGTSTP) /* ignored in vfork(2) */
+RAISE(raise4, SIGTTIN) /* ignored in vfork(2) */
+RAISE(raise5, SIGTTOU) /* ignored in vfork(2) */
+RAISE(raise6, SIGABRT) /* regular abort trap */
+RAISE(raise7, SIGHUP)  /* hangup */
+RAISE(raise8, SIGCONT) /* continued? */
+
+/// ----------------------------------------------------------------------------
+
+static int
+clone_func(void *arg __unused)
+{
+
+       return 0;
+}
+
+static void
+nested_raw(const char *fn, volatile int flags)
+{
+       int status;
+       pid_t child, child2, wpid;
+       const size_t stack_size = 1024 * 1024;
+       void *stack, *stack_base;
+                
+       stack = malloc(stack_size);
+       ATF_REQUIRE(stack != NULL);
+
+#ifdef __MACHINE_STACK_GROWS_UP
+       stack_base = stack;
+#else
+       stack_base = (char *)stack + stack_size;
+#endif
+
+       flags |= SIGCHLD;
+
+       child = FORK();
+       ATF_REQUIRE(child != 1);
+       if (child == 0) {
+               if (strcmp(fn, "fork") == 0)
+                       child2 = fork();
+               else if (strcmp(fn, "vfork") == 0)
+                       child2 = vfork();
+#ifndef __OpenBSD__
+               else if (strcmp(fn, "clone") == 0)
+                       child2 = __clone(clone_func, stack_base, flags, NULL);
+#endif
+               else
+                       __unreachable();
+
+               ASSERT_NEQ(child2, -1);
+
+               if ((strcmp(fn, "fork") == 0) || (strcmp(fn, "vfork") == 0)) {
+                       if (child2 == 0)
+                               _exit(0);
+               }
+
+               wpid = waitpid(child2, &status, 0);
+               ASSERT_EQ(child2, wpid);
+               ASSERT_EQ(!!WIFEXITED(status), true);
+               ASSERT_EQ(!!WIFCONTINUED(status), false);
+               ASSERT_EQ(!!WIFSIGNALED(status), false);
+               ASSERT_EQ(!!WIFSTOPPED(status), false);
+               ASSERT_EQ(WEXITSTATUS(status), 0);
+
+               _exit(0);
+       }
+       wpid = waitpid(child, &status, 0);
+
+       ATF_REQUIRE_EQ(wpid, child);
+       ATF_REQUIRE_EQ(!!WIFEXITED(status), true);
+       ATF_REQUIRE_EQ(!!WIFCONTINUED(status), false);
+       ATF_REQUIRE_EQ(!!WIFSIGNALED(status), false);
+       ATF_REQUIRE_EQ(!!WIFSTOPPED(status), false);
+       ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
+}
+
+#define NESTED(test, fn, flags)                                                        \
+ATF_TC(test);                                                                  \
+ATF_TC_HEAD(test, tc)                                                          \
+{                                                                              \
+                                                                               \
+       atf_tc_set_md_var(tc, "descr",                                          \
+           "Test nested " #fn " in a child");                                  \
+}                                                                              \
+                                                                               \
+ATF_TC_BODY(test, tc)                                                          \
+{                                                                              \
+                                                                               \
+       nested_raw(#fn, flags);                                                 \
+}
+
+NESTED(nested_fork, fork, 0)
+NESTED(nested_vfork, vfork, 0)
+#ifndef __OpenBSD__
+NESTED(nested_clone, clone, 0)
+NESTED(nested_clone_vm, clone, CLONE_VM)
+NESTED(nested_clone_fs, clone, CLONE_FS)
+NESTED(nested_clone_files, clone, CLONE_FILES)
+//NESTED(nested_clone_sighand, clone, CLONE_SIGHAND) // XXX
+NESTED(nested_clone_vfork, clone, CLONE_VFORK)
+#endif
+
+ATF_TP_ADD_TCS(tp)
+{
+       ATF_TP_ADD_TC(tp, raise1);
+       ATF_TP_ADD_TC(tp, raise2);
+       ATF_TP_ADD_TC(tp, raise3);
+       ATF_TP_ADD_TC(tp, raise4);
+       ATF_TP_ADD_TC(tp, raise5);
+       ATF_TP_ADD_TC(tp, raise6);
+       ATF_TP_ADD_TC(tp, raise7);
+       ATF_TP_ADD_TC(tp, raise8);
+
+       ATF_TP_ADD_TC(tp, nested_fork);
+       ATF_TP_ADD_TC(tp, nested_vfork);
+#ifndef __OpenBSD__
+       ATF_TP_ADD_TC(tp, nested_clone);
+       ATF_TP_ADD_TC(tp, nested_clone_vm);
+       ATF_TP_ADD_TC(tp, nested_clone_fs);
+       ATF_TP_ADD_TC(tp, nested_clone_files);
+//     ATF_TP_ADD_TC(tp, nested_clone_sighand); // XXX
+       ATF_TP_ADD_TC(tp, nested_clone_vfork);
+#endif
+
+       return atf_no_error();
+}
diff --git a/regress/lib/libc/sys/t_kevent.c b/regress/lib/libc/sys/t_kevent.c
new file mode 100644 (file)
index 0000000..171e1f3
--- /dev/null
@@ -0,0 +1,236 @@
+/*     $OpenBSD: t_kevent.c,v 1.1 2021/09/02 12:40:44 mbuhl Exp $      */
+/*     $NetBSD: t_kevent.c,v 1.9 2020/10/31 01:08:32 christos Exp $ */
+
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundatiom
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "macros.h"
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_kevent.c,v 1.9 2020/10/31 01:08:32 christos Exp $");
+
+#include <sys/types.h>
+#include <sys/event.h>
+
+#include "atf-c.h"
+#include <errno.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <err.h>
+#ifndef __OpenBSD__
+#include <sys/drvctlio.h>
+#endif
+#include <sys/event.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+ATF_TC(kevent_zerotimer);
+ATF_TC_HEAD(kevent_zerotimer, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Checks that kevent with a 0 timer "
+           "does not crash the system (PR lib/45618)");
+}
+
+ATF_TC_BODY(kevent_zerotimer, tc)
+{
+       struct kevent ev;
+       int kq;
+
+       ATF_REQUIRE((kq = kqueue()) != -1);
+       EV_SET(&ev, 1, EVFILT_TIMER, EV_ADD|EV_ENABLE, 0, 1, 0);
+       ATF_REQUIRE(kevent(kq, &ev, 1, NULL, 0, NULL) != -1);
+       ATF_REQUIRE(kevent(kq, NULL, 0, &ev, 1, NULL) == 1);
+}
+
+ATF_TC(kqueue_desc_passing);
+ATF_TC_HEAD(kqueue_desc_passing, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Checks that passing a kqueue to "
+               "another process does not crash the kernel (PR 46463)");
+}
+
+ATF_TC_BODY(kqueue_desc_passing, tc)
+{
+       pid_t child;
+       int s[2], storage, status, kq;
+       struct cmsghdr *msg;
+       struct iovec iov;
+       struct msghdr m;
+       struct kevent ev;
+
+       ATF_REQUIRE((kq = kqueue()) != -1);
+
+       // atf_tc_skip("crashes kernel (PR kern/46463)");
+
+       ATF_REQUIRE(socketpair(AF_LOCAL, SOCK_STREAM, 0, s) != -1);
+       msg = malloc(CMSG_SPACE(sizeof(int)));
+       m.msg_iov = &iov;
+       m.msg_iovlen = 1;
+       m.msg_name = NULL;
+       m.msg_namelen = 0;
+       m.msg_control = msg;
+       m.msg_controllen = CMSG_SPACE(sizeof(int));
+
+       child = fork();
+       if (child == 0) {
+#ifdef __OpenBSD__
+               sleep(1);
+               exit(0);
+#endif
+               close(s[0]);
+
+               iov.iov_base = &storage;
+               iov.iov_len = sizeof(int);
+               m.msg_iov = &iov;
+               m.msg_iovlen = 1;
+
+               if (recvmsg(s[1], &m, 0) == -1)
+                       err(1, "child: could not recvmsg");
+
+               kq = *(int *)CMSG_DATA(msg);
+               printf("child (pid %d): received kq fd %d\n", getpid(), kq);
+               exit(0);
+       }
+
+       close(s[1]);
+
+       iov.iov_base = &storage;
+       iov.iov_len = sizeof(int);
+
+       msg->cmsg_level = SOL_SOCKET;
+       msg->cmsg_type = SCM_RIGHTS;
+       msg->cmsg_len = CMSG_LEN(sizeof(int));
+
+       *(int *)CMSG_DATA(msg) = kq;
+
+       EV_SET(&ev, 1, EVFILT_TIMER, EV_ADD|EV_ENABLE, 0, 1, 0);
+       ATF_CHECK(kevent(kq, &ev, 1, NULL, 0, NULL) != -1);
+
+       printf("parent (pid %d): sending kq fd %d\n", getpid(), kq);
+       if (sendmsg(s[0], &m, 0) == -1) {
+#ifdef __OpenBSD__
+               ATF_REQUIRE_EQ_MSG(errno, EINVAL, "errno is %d", errno);
+#else
+               ATF_REQUIRE_EQ_MSG(errno, EBADF, "errno is %d", errno);
+               atf_tc_skip("PR kern/46523");
+#endif
+       }
+
+       close(kq);
+
+       waitpid(child, &status, 0);
+       ATF_CHECK(WIFEXITED(status) && WEXITSTATUS(status)==0);
+}
+
+#ifndef __OpenBSD__
+ATF_TC(kqueue_unsupported_fd);
+ATF_TC_HEAD(kqueue_unsupported_fd, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Checks that watching an fd whose"
+           " type is not supported does not crash the kernel");
+}
+
+ATF_TC_BODY(kqueue_unsupported_fd, tc)
+{
+       /* mqueue and semaphore use fnullop_kqueue also */
+       int fd, kq;
+       struct kevent ev;
+
+       fd = open(DRVCTLDEV, O_RDONLY);
+       if (fd == -1) {
+               switch (errno) {
+               case ENOENT:
+               case ENXIO:
+                       atf_tc_skip("no " DRVCTLDEV " available for testing");
+                       break;
+               }
+       }
+       ATF_REQUIRE(fd != -1);
+       ATF_REQUIRE((kq = kqueue()) != -1);
+
+       EV_SET(&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
+          NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK|
+          NOTE_RENAME|NOTE_REVOKE, 0, 0);
+
+       ATF_REQUIRE(kevent(kq, &ev, 1, NULL, 0, NULL) == -1);
+       ATF_REQUIRE_ERRNO(EOPNOTSUPP, true);
+
+       (void)close(fd);
+       (void)close(kq);
+}
+
+ATF_TC(kqueue_EVFILT_USER);
+ATF_TC_HEAD(kqueue_EVFILT_USER, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Checks usability of EVFILT_USER");
+}
+
+ATF_TC_BODY(kqueue_EVFILT_USER, tc)
+{
+       /* mqueue and semaphore use fnullop_kqueue also */
+       int kq;
+       struct kevent ev, rev;
+
+       ATF_REQUIRE((kq = kqueue()) != -1);
+
+       EV_SET(&ev, 666, EVFILT_USER, EV_ADD | EV_ENABLE, 0, 0, 0);
+       ATF_REQUIRE(kevent(kq, &ev, 1, NULL, 0, NULL) == 0);
+       EV_SET(&ev, 666, EVFILT_USER, 0, NOTE_FFCOPY | NOTE_TRIGGER | 8, 0, 0);
+       ATF_REQUIRE(kevent(kq, &ev, 1, NULL, 0, NULL) == 0);
+       const struct timespec timeout = {
+               .tv_sec = 1,
+               .tv_nsec = 0,
+       };
+
+       ATF_REQUIRE(kevent(kq, NULL, 0, &rev, 1, &timeout) == 1);
+       ATF_REQUIRE(rev.ident == 666);
+       ATF_REQUIRE(rev.filter == EVFILT_USER);
+       ATF_REQUIRE(rev.fflags == 8);
+       (void)close(kq);
+}
+#endif
+
+
+
+ATF_TP_ADD_TCS(tp)
+{
+
+       ATF_TP_ADD_TC(tp, kevent_zerotimer);
+       ATF_TP_ADD_TC(tp, kqueue_desc_passing);
+#ifndef __OpenBSD__
+       ATF_TP_ADD_TC(tp, kqueue_unsupported_fd);
+       ATF_TP_ADD_TC(tp, kqueue_EVFILT_USER);
+#endif
+
+       return atf_no_error();
+}
diff --git a/regress/lib/libc/sys/t_minherit.c b/regress/lib/libc/sys/t_minherit.c
new file mode 100644 (file)
index 0000000..dd9ddf1
--- /dev/null
@@ -0,0 +1,203 @@
+/*     $OpenBSD: t_minherit.c,v 1.1 2021/09/02 12:40:44 mbuhl Exp $    */
+/* $NetBSD: t_minherit.c,v 1.1 2014/07/18 12:34:52 christos Exp $ */
+
+/*-
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "macros.h"
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_minherit.c,v 1.1 2014/07/18 12:34:52 christos Exp $");
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "atf-c.h"
+
+static long page;
+
+static void *
+makemap(int v, int f) {
+       void *map = mmap(NULL, page, PROT_READ|PROT_WRITE,
+           MAP_SHARED|MAP_ANON, -1, 0);
+       ATF_REQUIRE(map != MAP_FAILED);
+       memset(map, v, page);
+       if (f != 666)
+               ATF_REQUIRE(minherit(map, page, f) == 0);
+       else
+               ATF_REQUIRE(minherit(map, page, f) == -1);
+       return map;
+}
+
+ATF_TC(minherit_copy);
+ATF_TC_HEAD(minherit_copy, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test for MAP_INHERIT_COPY from minherit(2)");
+}
+
+ATF_TC_BODY(minherit_copy, tc)
+{
+       void *map1 = makemap(1, MAP_INHERIT_COPY);
+       void *map2 = makemap(1, MAP_INHERIT_COPY);
+       switch (fork()) {
+       default:
+               ATF_REQUIRE(wait(NULL) != -1);
+               ATF_REQUIRE(memcmp(map1, map2, page) == 0);
+               break;
+       case -1:
+               ATF_REQUIRE(0);
+               break;
+       case 0:
+               ATF_REQUIRE(memcmp(map1, map2, page) == 0);
+               memset(map1, 0, page);
+               exit(0);
+       }
+}
+
+ATF_TC(minherit_share);
+ATF_TC_HEAD(minherit_share, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test for MAP_INHERIT_SHARE from minherit(2)");
+}
+
+ATF_TC_BODY(minherit_share, tc)
+{
+       void *map1 = makemap(1, MAP_INHERIT_SHARE);
+       void *map2 = makemap(1, MAP_INHERIT_SHARE);
+
+       switch (fork()) {
+       default:
+               ATF_REQUIRE(wait(NULL) != -1);
+               memset(map2, 0, page);
+               ATF_REQUIRE(memcmp(map1, map2, page) == 0);
+               break;
+       case -1:
+               ATF_REQUIRE(0);
+               break;
+       case 0:
+               ATF_REQUIRE(memcmp(map1, map2, page) == 0);
+               memset(map1, 0, page);
+               exit(0);
+       }
+}
+
+static void
+segv(int n) {
+       _exit(n);
+}
+
+ATF_TC(minherit_none);
+ATF_TC_HEAD(minherit_none, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test for MAP_INHERIT_NONE from minherit(2)");
+}
+
+ATF_TC_BODY(minherit_none, tc)
+{
+       void *map1 = makemap(0, MAP_INHERIT_NONE);
+       int status;
+
+       switch (fork()) {
+       default:
+               ATF_REQUIRE(wait(&status) != -1);
+               ATF_REQUIRE(WEXITSTATUS(status) == SIGSEGV);
+               break;
+       case -1:
+               ATF_REQUIRE(0);
+               break;
+       case 0:
+               ATF_REQUIRE(signal(SIGSEGV, segv) != SIG_ERR);
+               memset(map1, 0, page);
+               exit(0);
+       }
+}
+
+ATF_TC(minherit_zero);
+ATF_TC_HEAD(minherit_zero, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test for MAP_INHERIT_ZERO from minherit(2)");
+}
+
+ATF_TC_BODY(minherit_zero, tc)
+{
+       void *map1 = makemap(1, MAP_INHERIT_ZERO);
+       void *map2 = makemap(0, MAP_INHERIT_SHARE);
+
+       switch (fork()) {
+       default:
+               ATF_REQUIRE(wait(NULL) != -1);
+               memset(map2, 1, page);
+               ATF_REQUIRE(memcmp(map1, map2, page) == 0);
+               break;
+       case -1:
+               ATF_REQUIRE(0);
+               break;
+       case 0:
+               ATF_REQUIRE(memcmp(map1, map2, page) == 0);
+               memset(map1, 2, page);
+               exit(0);
+       }
+}
+
+ATF_TC(minherit_bad);
+ATF_TC_HEAD(minherit_bad, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test for bad minherit(2)");
+}
+
+ATF_TC_BODY(minherit_bad, tc)
+{
+       (void)makemap(0, 666);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+       page = sysconf(_SC_PAGESIZE);
+       ATF_REQUIRE(page >= 0);
+
+       ATF_TP_ADD_TC(tp, minherit_copy);
+       ATF_TP_ADD_TC(tp, minherit_share);
+       ATF_TP_ADD_TC(tp, minherit_none);
+       ATF_TP_ADD_TC(tp, minherit_zero);
+       ATF_TP_ADD_TC(tp, minherit_bad);
+
+       return atf_no_error();
+}
diff --git a/regress/lib/libc/sys/t_pollts.c b/regress/lib/libc/sys/t_pollts.c
new file mode 100644 (file)
index 0000000..966b8c7
--- /dev/null
@@ -0,0 +1,203 @@
+/*     $OpenBSD: t_pollts.c,v 1.1 2021/09/02 12:40:44 mbuhl Exp $      */
+/*     $NetBSD: t_pollts.c,v 1.1 2020/07/17 15:34:17 kamil Exp $       */
+
+/*-
+ * Copyright (c) 2011, 2020 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matthias Scheler.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "macros.h"
+
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include "atf-c.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <poll.h>
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+
+#ifndef POLLTS
+#define POLLTS pollts
+#endif
+
+ATF_TC(basic);
+ATF_TC_HEAD(basic, tc)
+{
+       atf_tc_set_md_var(tc, "timeout", "10");
+       atf_tc_set_md_var(tc, "descr",
+           "Basis functionality test for ppoll(2)/pollts(2)");
+}
+
+ATF_TC_BODY(basic, tc)
+{
+       int fds[2];
+       struct pollfd pfds[2];
+       struct timespec timeout;
+       int ret;
+
+       ATF_REQUIRE_EQ(pipe(fds), 0);
+
+       pfds[0].fd = fds[0];
+       pfds[0].events = POLLIN;
+       pfds[1].fd = fds[1];
+       pfds[1].events = POLLOUT;
+
+       /* Use a timeout of 1 second. */
+       timeout.tv_sec = 1;
+       timeout.tv_nsec = 0;
+
+       /*
+        * Check that we get a timeout waiting for data on the read end
+        * of our pipe.
+        */
+       pfds[0].revents = -1;
+       pfds[1].revents = -1;
+       ATF_REQUIRE_EQ_MSG(ret = POLLTS(&pfds[0], 1, &timeout, NULL), 0,
+           "got: %d", ret);
+       ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
+       ATF_REQUIRE_EQ_MSG(pfds[1].revents, -1, "got: %d", pfds[1].revents);
+
+       /* Check that the write end of the pipe as reported as ready. */
+       pfds[0].revents = -1;
+       pfds[1].revents = -1;
+       ATF_REQUIRE_EQ_MSG(ret = POLLTS(&pfds[1], 1, &timeout, NULL), 1,
+           "got: %d", ret);
+       ATF_REQUIRE_EQ_MSG(pfds[0].revents, -1, "got: %d", pfds[0].revents);
+       ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",\
+           pfds[1].revents);
+
+       /* Check that only the write end of the pipe as reported as ready. */
+       pfds[0].revents = -1;
+       pfds[1].revents = -1;
+       ATF_REQUIRE_EQ_MSG(ret = POLLTS(pfds, 2, &timeout, NULL), 1,
+           "got: %d", ret);
+       ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
+       ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
+           pfds[1].revents);
+
+       /* Write data to our pipe. */
+       ATF_REQUIRE_EQ(write(fds[1], "", 1), 1);
+
+       /* Check that both ends of our pipe are reported as ready. */
+       pfds[0].revents = -1;
+       pfds[1].revents = -1;
+       ATF_REQUIRE_EQ_MSG(ret = POLLTS(pfds, 2, &timeout, NULL), 2,
+           "got: %d", ret);
+       ATF_REQUIRE_EQ_MSG(pfds[0].revents, POLLIN, "got: %d",
+           pfds[0].revents);
+       ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
+           pfds[1].revents);
+
+       ATF_REQUIRE_EQ(close(fds[0]), 0);
+       ATF_REQUIRE_EQ(close(fds[1]), 0);
+}
+
+ATF_TC(err);
+ATF_TC_HEAD(err, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Check errors from ppoll(2)/pollts(2)");
+}
+
+ATF_TC_BODY(err, tc)
+{
+       struct timespec timeout;
+       struct pollfd pfd;
+       int fd = 0;
+
+       pfd.fd = fd;
+       pfd.events = POLLIN;
+
+       timeout.tv_sec = 1;
+       timeout.tv_nsec = 0;
+
+       errno = 0;
+       ATF_REQUIRE_ERRNO(EFAULT, POLLTS((void *)-1, 1, &timeout, NULL) == -1);
+
+       timeout.tv_sec = -1;
+       timeout.tv_nsec = -1;
+
+       errno = 0;
+       ATF_REQUIRE_ERRNO(EINVAL, POLLTS(&pfd, 1, &timeout, NULL) == -1);
+}
+
+ATF_TC(sigmask);
+ATF_TC_HEAD(sigmask, tc)
+{
+       atf_tc_set_md_var(tc, "timeout", "10");
+       atf_tc_set_md_var(tc, "descr",
+           "Check that ppoll(2)/pollts(2) restores the signal mask (PR kern/44986)");
+}
+
+ATF_TC_BODY(sigmask, tc)
+{
+       int fd;
+       struct pollfd pfd;
+       struct timespec timeout;
+       sigset_t mask;
+       int ret;
+
+       fd = open(_PATH_DEVNULL, O_RDONLY);
+       ATF_REQUIRE(fd >= 0);
+
+       pfd.fd = fd;
+       pfd.events = POLLIN;
+
+       /* Use a timeout of 1 second. */
+       timeout.tv_sec = 1;
+       timeout.tv_nsec = 0;
+
+       /* Unblock all signals. */
+       ATF_REQUIRE_EQ(sigfillset(&mask), 0);
+       ATF_REQUIRE_EQ(sigprocmask(SIG_UNBLOCK, &mask, NULL), 0);
+
+       /*
+        * Check that ppoll(2)/pollts(2) immediately returns. We block *all*
+        * signals during ppoll(2)/pollts(2).
+        */
+       ATF_REQUIRE_EQ_MSG(ret = POLLTS(&pfd, 1, &timeout, &mask), 1,
+           "got: %d", ret);
+
+       /* Check that signals are now longer blocked. */
+       ATF_REQUIRE_EQ(sigprocmask(SIG_SETMASK, NULL, &mask), 0);
+       ATF_REQUIRE_EQ_MSG(sigismember(&mask, SIGUSR1), 0,
+           "signal mask was changed.");
+
+       ATF_REQUIRE_EQ(close(fd), 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+       ATF_TP_ADD_TC(tp, basic);
+       ATF_TP_ADD_TC(tp, err);
+       ATF_TP_ADD_TC(tp, sigmask);
+
+       return atf_no_error();
+}
diff --git a/regress/lib/libc/sys/t_ppoll.c b/regress/lib/libc/sys/t_ppoll.c
new file mode 100644 (file)
index 0000000..c5daef1
--- /dev/null
@@ -0,0 +1,34 @@
+/*     $OpenBSD: t_ppoll.c,v 1.1 2021/09/02 12:40:44 mbuhl Exp $       */
+/*     $NetBSD: t_ppoll.c,v 1.1 2020/07/17 15:34:17 kamil Exp $        */
+
+/*-
+ * Copyright (c) 2011, 2020 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matthias Scheler.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define POLLTS ppoll
+#include "t_pollts.c"
diff --git a/regress/lib/libc/sys/t_setrlimit.c b/regress/lib/libc/sys/t_setrlimit.c
new file mode 100644 (file)
index 0000000..d72ec52
--- /dev/null
@@ -0,0 +1,559 @@
+/*     $OpenBSD: t_setrlimit.c,v 1.1 2021/09/02 12:40:44 mbuhl Exp $   */
+/* $NetBSD: t_setrlimit.c,v 1.7 2020/10/13 06:58:57 rin Exp $ */
+
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jukka Ruohonen.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "macros.h"
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_setrlimit.c,v 1.7 2020/10/13 06:58:57 rin Exp $");
+
+#include <sys/resource.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+#include "atf-c.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#ifndef __OpenBSD__
+#include <lwp.h>
+#endif
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef __OpenBSD__
+#include <ucontext.h>
+#endif
+#include <unistd.h>
+
+static void             sighandler(int);
+static const char       path[] = "setrlimit";
+
+static const int rlimit[] = {
+#ifndef __OpenBSD__
+       RLIMIT_AS,
+#endif
+       RLIMIT_CORE,
+       RLIMIT_CPU,
+       RLIMIT_DATA,
+       RLIMIT_FSIZE,
+       RLIMIT_MEMLOCK,
+       RLIMIT_NOFILE,
+       RLIMIT_NPROC,
+       RLIMIT_RSS,
+#ifndef __OpenBSD__
+       RLIMIT_SBSIZE,
+#endif
+       RLIMIT_STACK
+};
+
+ATF_TC(setrlimit_basic);
+ATF_TC_HEAD(setrlimit_basic, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "A basic soft limit test");
+}
+
+ATF_TC_BODY(setrlimit_basic, tc)
+{
+       struct rlimit res;
+       int *buf, lim;
+       size_t i;
+
+       buf = calloc(__arraycount(rlimit), sizeof(int));
+
+       if (buf == NULL)
+               atf_tc_fail("initialization failed");
+
+       for (i = lim = 0; i < __arraycount(rlimit); i++) {
+
+               (void)memset(&res, 0, sizeof(struct rlimit));
+
+               if (getrlimit(rlimit[i], &res) != 0)
+                       continue;
+
+               if (res.rlim_cur == RLIM_INFINITY || res.rlim_cur == 0)
+                       continue;
+
+               if (res.rlim_cur == res.rlim_max) /* An unprivileged run. */
+                       continue;
+
+               buf[i] = res.rlim_cur;
+               res.rlim_cur = res.rlim_cur - 1;
+
+               if (setrlimit(rlimit[i], &res) != 0) {
+                       lim = rlimit[i];
+                       goto out;
+               }
+       }
+
+out:
+       for (i = 0; i < __arraycount(rlimit); i++) {
+
+               (void)memset(&res, 0, sizeof(struct rlimit));
+
+               if (buf[i] == 0)
+                       continue;
+
+               if (getrlimit(rlimit[i], &res) != 0)
+                       continue;
+
+               res.rlim_cur = buf[i];
+
+               (void)setrlimit(rlimit[i], &res);
+       }
+
+       if (lim != 0)
+               atf_tc_fail("failed to set limit (%d)", lim);
+       free(buf);
+}
+
+ATF_TC(setrlimit_current);
+ATF_TC_HEAD(setrlimit_current, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "setrlimit(3) with current limits");
+}
+
+ATF_TC_BODY(setrlimit_current, tc)
+{
+       struct rlimit res;
+       size_t i;
+
+       for (i = 0; i < __arraycount(rlimit); i++) {
+
+               (void)memset(&res, 0, sizeof(struct rlimit));
+
+               ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0);
+               ATF_REQUIRE(setrlimit(rlimit[i], &res) == 0);
+       }
+}
+
+ATF_TC(setrlimit_err);
+ATF_TC_HEAD(setrlimit_err, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Test error conditions");
+}
+
+ATF_TC_BODY(setrlimit_err, tc)
+{
+       struct rlimit res;
+       size_t i;
+
+       for (i = 0; i < __arraycount(rlimit); i++) {
+
+               errno = 0;
+
+               ATF_REQUIRE(getrlimit(rlimit[i], (void *)0) != 0);
+               ATF_REQUIRE(errno == EFAULT);
+       }
+
+       errno = 0;
+
+       ATF_REQUIRE(getrlimit(INT_MAX, &res) != 0);
+       ATF_REQUIRE(errno == EINVAL);
+}
+
+ATF_TC_WITH_CLEANUP(setrlimit_fsize);
+ATF_TC_HEAD(setrlimit_fsize, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_FSIZE");
+}
+
+ATF_TC_BODY(setrlimit_fsize, tc)
+{
+       struct rlimit res;
+       int fd, sta;
+       pid_t pid;
+
+       fd = open(path, O_RDWR | O_CREAT, 0700);
+
+       if (fd < 0)
+               atf_tc_fail("initialization failed");
+
+       pid = fork();
+       ATF_REQUIRE(pid >= 0);
+
+       if (pid == 0) {
+
+               res.rlim_cur = 2;
+               res.rlim_max = 2;
+
+               if (setrlimit(RLIMIT_FSIZE, &res) != 0)
+                       _exit(EXIT_FAILURE);
+
+               if (signal(SIGXFSZ, sighandler) == SIG_ERR)
+                       _exit(EXIT_FAILURE);
+
+               /*
+                * The third call should generate a SIGXFSZ.
+                */
+               (void)write(fd, "X", 1);
+               (void)write(fd, "X", 1);
+               (void)write(fd, "X", 1);
+
+               _exit(EXIT_FAILURE);
+       }
+
+       (void)close(fd);
+       (void)wait(&sta);
+       (void)unlink(path);
+
+       if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
+               atf_tc_fail("RLIMIT_FSIZE not enforced");
+}
+
+ATF_TC_CLEANUP(setrlimit_fsize, tc)
+{
+       (void)unlink(path);
+}
+
+static void
+sighandler(int signo)
+{
+
+       if (signo != SIGXFSZ)
+               _exit(EXIT_FAILURE);
+
+       _exit(EXIT_SUCCESS);
+}
+
+ATF_TC(setrlimit_memlock);
+ATF_TC_HEAD(setrlimit_memlock, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_MEMLOCK");
+}
+
+ATF_TC_BODY(setrlimit_memlock, tc)
+{
+       struct rlimit res;
+       void *buf;
+       long page;
+       pid_t pid;
+       int sta;
+
+       page = sysconf(_SC_PAGESIZE);
+       ATF_REQUIRE(page >= 0);
+
+       buf = malloc(page);
+       pid = fork();
+
+       if (buf == NULL || pid < 0)
+               atf_tc_fail("initialization failed");
+
+       if (pid == 0) {
+
+               /*
+                * Try to lock a page while
+                * RLIMIT_MEMLOCK is zero.
+                */
+               if (mlock(buf, page) != 0)
+                       _exit(EXIT_FAILURE);
+
+               if (munlock(buf, page) != 0)
+                       _exit(EXIT_FAILURE);
+
+               res.rlim_cur = 0;
+               res.rlim_max = 0;
+
+               if (setrlimit(RLIMIT_MEMLOCK, &res) != 0)
+                       _exit(EXIT_FAILURE);
+
+               if (mlock(buf, page) != 0)
+                       _exit(EXIT_SUCCESS);
+
+               (void)munlock(buf, page);
+
+               _exit(EXIT_FAILURE);
+       }
+
+       free(buf);
+
+       (void)wait(&sta);
+
+       if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
+               atf_tc_fail("RLIMIT_MEMLOCK not enforced");
+}
+
+ATF_TC(setrlimit_nofile_1);
+ATF_TC_HEAD(setrlimit_nofile_1, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #1");
+}
+
+ATF_TC_BODY(setrlimit_nofile_1, tc)
+{
+       struct rlimit res;
+       int fd, i, rv, sta;
+       pid_t pid;
+
+       res.rlim_cur = 0;
+       res.rlim_max = 0;
+
+       pid = fork();
+       ATF_REQUIRE(pid >= 0);
+
+       if (pid == 0) {
+
+               /*
+                * Close all descriptors, set RLIMIT_NOFILE
+                * to zero, and try to open a random file.
+                * This should fail with EMFILE.
+                */
+               for (i = 0; i < 1024; i++)
+                       (void)close(i);
+
+               rv = setrlimit(RLIMIT_NOFILE, &res);
+
+               if (rv != 0)
+                       _exit(EXIT_FAILURE);
+
+               errno = 0;
+               fd = open("/etc/passwd", O_RDONLY);
+
+               if (fd >= 0 || errno != EMFILE)
+                       _exit(EXIT_FAILURE);
+
+               _exit(EXIT_SUCCESS);
+       }
+
+       (void)wait(&sta);
+
+       if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
+               atf_tc_fail("RLIMIT_NOFILE not enforced");
+}
+
+ATF_TC(setrlimit_nofile_2);
+ATF_TC_HEAD(setrlimit_nofile_2, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #2");
+}
+
+ATF_TC_BODY(setrlimit_nofile_2, tc)
+{
+       static const rlim_t lim = 12;
+       struct rlimit res;
+       int fd, i, rv, sta;
+       pid_t pid;
+
+       /*
+        * See that an arbitrary limit on
+        * open files is being enforced.
+        */
+       res.rlim_cur = lim;
+       res.rlim_max = lim;
+
+       pid = fork();
+       ATF_REQUIRE(pid >= 0);
+
+       if (pid == 0) {
+
+               for (i = 0; i < 1024; i++)
+                       (void)close(i);
+
+               rv = setrlimit(RLIMIT_NOFILE, &res);
+
+               if (rv != 0)
+                       _exit(EXIT_FAILURE);
+
+               for (i = 0; i < (int)lim; i++) {
+
+                       fd = open("/etc/passwd", O_RDONLY);
+
+                       if (fd < 0)
+                               _exit(EXIT_FAILURE);
+               }
+
+               /*
+                * After the limit has been reached,
+                * EMFILE should again follow.
+                */
+               fd = open("/etc/passwd", O_RDONLY);
+
+               if (fd >= 0 || errno != EMFILE)
+                       _exit(EXIT_FAILURE);
+
+               _exit(EXIT_SUCCESS);
+       }
+
+       (void)wait(&sta);
+
+       if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
+               atf_tc_fail("RLIMIT_NOFILE not enforced");
+}
+
+ATF_TC(setrlimit_nproc);
+ATF_TC_HEAD(setrlimit_nproc, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NPROC");
+       atf_tc_set_md_var(tc, "require.user", "unprivileged");
+}
+
+ATF_TC_BODY(setrlimit_nproc, tc)
+{
+       struct rlimit res;
+       pid_t pid, cpid;
+       int sta;
+
+       pid = fork();
+       ATF_REQUIRE(pid >= 0);
+
+       if (pid == 0) {
+
+               /*
+                * Set RLIMIT_NPROC to zero and try to fork.
+                */
+               res.rlim_cur = 0;
+               res.rlim_max = 0;
+
+               if (setrlimit(RLIMIT_NPROC, &res) != 0)
+                       _exit(EXIT_FAILURE);
+
+               cpid = fork();
+
+               if (cpid < 0)
+                       _exit(EXIT_SUCCESS);
+
+               _exit(EXIT_FAILURE);
+       }
+
+       (void)waitpid(pid, &sta, 0);
+
+       if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
+               atf_tc_fail("RLIMIT_NPROC not enforced");
+}
+
+#ifndef __OpenBSD__
+
+ATF_TC(setrlimit_nthr);
+ATF_TC_HEAD(setrlimit_nthr, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NTHR");
+       atf_tc_set_md_var(tc, "require.user", "unprivileged");
+}
+
+static void
+func(lwpid_t *id)
+{
+       printf("thread %d\n", *id);
+       fflush(stdout);
+       _lwp_exit();
+}
+
+ATF_TC_BODY(setrlimit_nthr, tc)
+{
+       struct rlimit res;
+       lwpid_t lwpid;
+       ucontext_t c;
+
+       /*
+        * Set RLIMIT_NTHR to zero and try to create a thread.
+        */
+       res.rlim_cur = 0;
+       res.rlim_max = 0;
+       ATF_REQUIRE(setrlimit(RLIMIT_NTHR, &res) == 0);
+       ATF_REQUIRE(getcontext(&c) == 0);
+       c.uc_link = NULL;
+       sigemptyset(&c.uc_sigmask);
+       c.uc_stack.ss_flags = 0;
+       c.uc_stack.ss_size = 4096;
+       ATF_REQUIRE((c.uc_stack.ss_sp = malloc(c.uc_stack.ss_size)) != NULL);
+       makecontext(&c, func, 1, &lwpid);
+       ATF_CHECK_ERRNO(EAGAIN, _lwp_create(&c, 0, &lwpid) == -1);
+}
+#endif
+
+ATF_TC(setrlimit_perm);
+ATF_TC_HEAD(setrlimit_perm, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Test setrlimit(2) for EPERM");
+       atf_tc_set_md_var(tc, "require.user", "unprivileged");
+}
+
+ATF_TC_BODY(setrlimit_perm, tc)
+{
+       struct rlimit res;
+       size_t i;
+
+       /*
+        * Try to raise the maximum limits as an user.
+        */
+       for (i = 0; i < __arraycount(rlimit); i++) {
+
+               ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0);
+
+               if (res.rlim_max == UINT64_MAX) /* Overflow. */
+                       continue;
+
+               errno = 0;
+               res.rlim_max = res.rlim_max + 1;
+
+               ATF_CHECK_ERRNO(EPERM, setrlimit(rlimit[i], &res) != 0);
+       }
+}
+
+ATF_TC(setrlimit_stack);
+ATF_TC_HEAD(setrlimit_stack, tc)
+{
+       atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_STACK");
+       atf_tc_set_md_var(tc, "require.user", "unprivileged");
+}
+
+ATF_TC_BODY(setrlimit_stack, tc)
+{
+       struct rlimit res;
+
+       /* Ensure soft limit is not bigger than hard limit */
+       res.rlim_cur = res.rlim_max = 6 * 1024 * 1024;
+       ATF_REQUIRE(setrlimit(RLIMIT_STACK, &res) == 0);
+       ATF_REQUIRE(getrlimit(RLIMIT_STACK, &res) == 0);
+       ATF_CHECK(res.rlim_cur <= res.rlim_max);
+
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+       ATF_TP_ADD_TC(tp, setrlimit_basic);
+       ATF_TP_ADD_TC(tp, setrlimit_current);
+       ATF_TP_ADD_TC(tp, setrlimit_err);
+       ATF_TP_ADD_TC(tp, setrlimit_fsize);
+       ATF_TP_ADD_TC(tp, setrlimit_memlock);
+       ATF_TP_ADD_TC(tp, setrlimit_nofile_1);
+       ATF_TP_ADD_TC(tp, setrlimit_nofile_2);
+       ATF_TP_ADD_TC(tp, setrlimit_nproc);
+       ATF_TP_ADD_TC(tp, setrlimit_perm);
+#ifndef __OpenBSD__
+       ATF_TP_ADD_TC(tp, setrlimit_nthr);
+#endif
+       ATF_TP_ADD_TC(tp, setrlimit_stack);
+
+       return atf_no_error();
+}
diff --git a/regress/lib/libc/sys/t_sigaltstack.c b/regress/lib/libc/sys/t_sigaltstack.c
new file mode 100644 (file)
index 0000000..ac02650
--- /dev/null
@@ -0,0 +1,102 @@
+/*     $OpenBSD: t_sigaltstack.c,v 1.1 2021/09/02 12:40:44 mbuhl Exp $ */
+/* $NetBSD: t_sigaltstack.c,v 1.2 2020/05/01 21:35:30 christos Exp $ */
+
+/*-
+ * Copyright (c) 2020 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "macros.h"
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_sigaltstack.c,v 1.2 2020/05/01 21:35:30 christos Exp $");
+
+#include <signal.h>
+#include <stdbool.h>
+
+#include "atf-c.h"
+
+#include "h_macros.h"
+
+static stack_t sigstk;
+static bool handler_called;
+static bool handler_use_altstack;
+
+static void
+handler(int signo __unused)
+{
+       char sp[128];
+
+       handler_called = true;
+
+       /* checking if the stack pointer is within the range of altstack */
+       if ((char *)sigstk.ss_sp <= sp &&
+           ((char *)sigstk.ss_sp + sigstk.ss_size) > sp)
+               handler_use_altstack = true;
+       else
+               handler_use_altstack = false;
+}
+
+ATF_TC(sigaltstack_onstack);
+ATF_TC_HEAD(sigaltstack_onstack, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Checks for using signal stack with SA_ONSTACK");
+}
+
+ATF_TC_BODY(sigaltstack_onstack, tc)
+{
+       struct sigaction sa;
+       int i;
+
+       /* set a signal handler use alternative stack */
+       memset(&sigstk, 0, sizeof(sigstk));
+       sigstk.ss_sp = malloc(SIGSTKSZ);
+       ATF_REQUIRE(sigstk.ss_sp != NULL);
+       sigstk.ss_size = SIGSTKSZ;
+       sigstk.ss_flags = 0;
+       ATF_REQUIRE(sigaltstack(&sigstk, 0) == 0);
+
+       sigemptyset(&sa.sa_mask);
+       sa.sa_handler = handler;
+       sa.sa_flags = SA_ONSTACK;
+       sigaction(SIGUSR1, &sa, NULL);
+
+       /* test several times */
+       for (i = 1; i <= 5; i++) {
+               handler_called = false;
+               kill(getpid(), SIGUSR1);
+
+               if (!handler_called)
+                       atf_tc_fail("signal handler wasn't called (count=%d)", i);
+               if (!handler_use_altstack)
+                       atf_tc_fail("alternative stack wasn't used (count=%d)", i);
+       }
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+       ATF_TP_ADD_TC(tp, sigaltstack_onstack);
+
+       return atf_no_error();
+}
index 72ad913..4549058 100644 (file)
@@ -1,5 +1,5 @@
-/*     $OpenBSD: t_syscall.c,v 1.2 2020/11/10 14:43:14 bluhm Exp $     */
-/*     $NetBSD: t_syscall.c,v 1.3 2018/05/28 07:55:56 martin Exp $     */
+/*     $OpenBSD: t_syscall.c,v 1.3 2021/09/02 12:40:44 mbuhl Exp $     */
+/*     $NetBSD: t_syscall.c,v 1.4 2021/01/18 05:44:20 simonb Exp $     */
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -33,7 +33,7 @@
 #include "macros.h"
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: t_syscall.c,v 1.3 2018/05/28 07:55:56 martin Exp $");
+__RCSID("$NetBSD: t_syscall.c,v 1.4 2021/01/18 05:44:20 simonb Exp $");
 
 
 #include "atf-c.h"
@@ -84,7 +84,7 @@ ATF_TC_BODY(mmap_syscall, tc)
 
        p = (const char *)syscall(SYS_mmap,
                0, sizeof(secrect_data), PROT_READ, MAP_PRIVATE, fd, 0, 0, 0);
-       ATF_REQUIRE(p != NULL);
+       ATF_REQUIRE(p != MAP_FAILED);
 
        ATF_REQUIRE(strcmp(p, secrect_data) == 0);
 }
@@ -110,7 +110,7 @@ ATF_TC_BODY(mmap___syscall, tc)
        p = (const char *)__SYSCALL_TO_UINTPTR_T(__syscall(SYS_mmap,
                0, sizeof(secrect_data), PROT_READ, MAP_PRIVATE, fd,
                /* pad*/ 0, (off_t)0));
-       ATF_REQUIRE(p != NULL);
+       ATF_REQUIRE(p != MAP_FAILED);
 
        ATF_REQUIRE(strcmp(p, secrect_data) == 0);
 }
diff --git a/regress/lib/libc/sys/t_wait_noproc.c b/regress/lib/libc/sys/t_wait_noproc.c
new file mode 100644 (file)
index 0000000..73fc7ae
--- /dev/null
@@ -0,0 +1,364 @@
+/*     $OpenBSD: t_wait_noproc.c,v 1.1 2021/09/02 12:40:44 mbuhl Exp $ */
+/* $NetBSD: t_wait_noproc.c,v 1.5 2016/11/09 17:50:19 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "macros.h"
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_wait_noproc.c,v 1.5 2016/11/09 17:50:19 kamil Exp $");
+
+#include <sys/wait.h>
+#include <sys/resource.h>
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "atf-c.h"
+
+#ifndef TWAIT_OPTION
+#define TWAIT_OPTION 0
+#endif
+
+#if TWAIT_OPTION == 0
+ATF_TC(wait);
+ATF_TC_HEAD(wait, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test that wait(2) returns ECHILD for no child");
+}
+
+ATF_TC_BODY(wait, tc)
+{
+       ATF_REQUIRE_ERRNO(ECHILD, wait(NULL) == -1);
+}
+#endif
+
+ATF_TC(waitpid);
+ATF_TC_HEAD(waitpid, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test that waitpid(2) returns ECHILD for WAIT_ANY and option %s",
+           ___STRING(TWAIT_OPTION));
+}
+
+ATF_TC_BODY(waitpid, tc)
+{
+       ATF_REQUIRE_ERRNO(ECHILD, waitpid(WAIT_ANY, NULL, TWAIT_OPTION) == -1);
+}
+
+#ifndef __OpenBSD__
+ATF_TC(waitid);
+ATF_TC_HEAD(waitid, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test that waitid(2) returns ECHILD for P_ALL and option %s",
+           ___STRING(TWAIT_OPTION));
+}
+
+ATF_TC_BODY(waitid, tc)
+{
+       ATF_REQUIRE_ERRNO(ECHILD,
+           waitid(P_ALL, 0, NULL,
+               WTRAPPED | WEXITED | TWAIT_OPTION) == -1);
+}
+#endif
+
+ATF_TC(wait3);
+ATF_TC_HEAD(wait3, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test that wait3(2) returns ECHILD for no child");
+}
+
+ATF_TC_BODY(wait3, tc)
+{
+       ATF_REQUIRE_ERRNO(ECHILD, wait3(NULL, TWAIT_OPTION, NULL) == -1);
+}
+
+ATF_TC(wait4);
+ATF_TC_HEAD(wait4, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test that wait4(2) returns ECHILD for WAIT_ANY and option %s",
+           ___STRING(TWAIT_OPTION));
+}
+
+ATF_TC_BODY(wait4, tc)
+{
+       ATF_REQUIRE_ERRNO(ECHILD,
+           wait4(WAIT_ANY, NULL, TWAIT_OPTION, NULL) == -1);
+}
+
+#ifndef __OpenBSD__
+ * Adjusted for OpenBSD, not available
+ * ATF_TC(wait6);
+ * ATF_TC_HEAD(wait6, tc)
+ * {
+ *     atf_tc_set_md_var(tc, "descr",
+ *         "Test that wait6(2) returns ECHILD for P_ALL and option %s",
+ *         ___STRING(TWAIT_OPTION));
+ * }
+ * 
+ * ATF_TC_BODY(wait6, tc)
+ * {
+ *     ATF_REQUIRE_ERRNO(ECHILD,
+ *         wait6(P_ALL, 0, NULL,
+ *             WTRAPPED | WEXITED | TWAIT_OPTION, NULL, NULL) == -1);
+ * }
+ */
+
+/*
+ * Generator of valid combinations of options
+ * Usage: i = 0; while ((o = get_options_wait6(i++)) != -1) {}
+ */
+static int
+get_options6(size_t pos)
+{
+       int rv = 0;
+       size_t n;
+       /*
+        * waitid(2) must specify at least one of WEXITED, WUNTRACED,
+        * WSTOPPED, WTRAPPED or WCONTINUED. Single option WNOWAIT
+        * isn't valid.
+        */
+       const int matrix[] = {
+               WNOWAIT,        // First in order to blacklist it easily
+               WEXITED,
+               WUNTRACED,
+               WSTOPPED,       // SUS compatibility, equal to WUNTRACED
+               WTRAPPED,
+               WCONTINUED
+       };
+
+       const size_t M = (1 << __arraycount(matrix)) - 1;
+       /* Skip empty and sole WNOWAIT option */
+       pos+=2;
+
+       if (pos > M)
+               return -1;
+
+       for (n = 0; n < __arraycount(matrix); n++) {
+               if (pos & __BIT(n))
+                       rv |= matrix[n];
+       }
+
+       return rv;
+}
+#endif
+
+/*
+ * Generator of valid combinations of options
+ * Usage: i = 0; while ((o = get_options_wait4(i++)) != -1) {}
+ */
+static int
+get_options4(size_t pos)
+{
+       int rv = 0;
+       size_t n;
+
+       const int special[] = {
+               0,
+#ifndef __OpenBSD__
+               WALLSIG,
+               WALTSIG,
+               __WALL,         // Linux compatibility, equal to WALLSIG
+               __WCLONE        // Linux compatibility, equal to WALTSIG
+#endif
+       };
+
+       const int matrix[] = {
+#ifndef __OpenBSD__
+               WNOWAIT,
+               WEXITED,
+#endif
+               WUNTRACED,
+#ifndef __OpenBSD__
+               WSTOPPED,       // SUS compatibility, equal to WUNTRACED
+               WTRAPPED,
+#endif
+               WCONTINUED
+       };
+
+       const size_t M = (1 << __arraycount(special)) - 1;
+
+       if (pos < __arraycount(special))
+               return special[pos];
+
+       pos -= __arraycount(special);
+
+       ++pos; /* Don't start with empty mask */
+
+       if (pos > M)
+               return -1;
+
+       for (n = 0; n < __arraycount(special); n++) {
+               if (pos & __BIT(n))
+                       rv |= matrix[n];
+       }
+
+       return rv;
+}
+
+ATF_TC(waitpid_options);
+ATF_TC_HEAD(waitpid_options, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test that waitpid(2) returns ECHILD for WAIT_ANY and valid "
+           "combination of options with%s WNOHANG",
+           TWAIT_OPTION == 0 ? "out" : "");
+}
+
+ATF_TC_BODY(waitpid_options, tc)
+{
+       size_t i = 0;
+       int o;
+
+       while((o = get_options4(i++)) != -1) {
+               printf("Testing waitpid(2) with options %x\n", o);
+
+               ATF_REQUIRE_ERRNO(ECHILD,
+                   waitpid(WAIT_ANY, NULL, o | TWAIT_OPTION) == -1);
+       }
+}
+
+#ifndef __OpenBSD__
+ATF_TC(waitid_options);
+ATF_TC_HEAD(waitid_options, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test that waitid(2) returns ECHILD for P_ALL and valid "
+           "combination of options with%s WNOHANG",
+           TWAIT_OPTION == 0 ? "out" : "");
+}
+
+ATF_TC_BODY(waitid_options, tc)
+{
+       size_t i = 0;
+       int o;
+
+       while((o = get_options6(i++)) != -1) {
+               printf("Testing waitid(2) with options %x\n", o);
+
+               ATF_REQUIRE_ERRNO(ECHILD,
+                   waitid(P_ALL, 0, NULL, o | TWAIT_OPTION) == -1);
+       }
+}
+#endif
+
+ATF_TC(wait3_options);
+ATF_TC_HEAD(wait3_options, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test that wait3(2) returns ECHILD for no child");
+}
+
+ATF_TC_BODY(wait3_options, tc)
+{
+       size_t i = 0;
+       int o;
+
+       while((o = get_options4(i++)) != -1) {
+               printf("Testing wait3(2) with options %x\n", o);
+
+               ATF_REQUIRE_ERRNO(ECHILD,
+                   wait3(NULL, o | TWAIT_OPTION, NULL) == -1);
+       }
+}
+
+ATF_TC(wait4_options);
+ATF_TC_HEAD(wait4_options, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test that wait4(2) returns ECHILD for WAIT_ANY and option %s",
+           ___STRING(TWAIT_OPTION));
+}
+
+ATF_TC_BODY(wait4_options, tc)
+{
+       size_t i = 0;
+       int o;
+
+       while((o = get_options4(i++)) != -1) {
+               printf("Testing wait4(2) with options %x\n", o);
+
+               ATF_REQUIRE_ERRNO(ECHILD,
+                   wait4(WAIT_ANY, NULL, o | TWAIT_OPTION, NULL) == -1);
+       }
+}
+
+#ifndef __OpenBSD__
+ATF_TC(wait6_options);
+ATF_TC_HEAD(wait6_options, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Test that wait6(2) returns ECHILD for P_ALL and option %s",
+           ___STRING(TWAIT_OPTION));
+}
+
+ATF_TC_BODY(wait6_options, tc)
+{
+       size_t i = 0;
+       int o;
+
+       while((o = get_options6(i++)) != -1) {
+               printf("Testing wait6(2) with options %x\n", o);
+
+               ATF_REQUIRE_ERRNO(ECHILD,
+                   wait6(P_ALL, 0, NULL, o | TWAIT_OPTION, NULL, NULL) == -1);
+       }
+}
+#endif
+
+ATF_TP_ADD_TCS(tp)
+{
+
+#if TWAIT_OPTION == 0
+       ATF_TP_ADD_TC(tp, wait);
+#endif
+       ATF_TP_ADD_TC(tp, waitpid);
+#ifndef __OpenBSD__
+       ATF_TP_ADD_TC(tp, waitid);
+#endif
+       ATF_TP_ADD_TC(tp, wait3);
+       ATF_TP_ADD_TC(tp, wait4);
+#ifndef __OpenBSD__
+       ATF_TP_ADD_TC(tp, wait6);
+#endif
+
+       ATF_TP_ADD_TC(tp, waitpid_options);
+#ifndef __OpenBSD__
+       ATF_TP_ADD_TC(tp, waitid_options);
+#endif
+       ATF_TP_ADD_TC(tp, wait3_options);
+       ATF_TP_ADD_TC(tp, wait4_options);
+#ifndef __OpenBSD__
+       ATF_TP_ADD_TC(tp, wait6_options);
+#endif
+
+       return atf_no_error();
+}
diff --git a/regress/lib/libc/sys/t_wait_noproc_wnohang.c b/regress/lib/libc/sys/t_wait_noproc_wnohang.c
new file mode 100644 (file)
index 0000000..d1dcb98
--- /dev/null
@@ -0,0 +1,31 @@
+/*     $OpenBSD: t_wait_noproc_wnohang.c,v 1.1 2021/09/02 12:40:44 mbuhl Exp $ */
+/* $NetBSD: t_wait_noproc_wnohang.c,v 1.1 2016/11/06 15:03:30 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define TWAIT_OPTION WNOHANG
+#include "t_wait_noproc.c"