1/* $OpenBSD: t_waitid.c,v 1.1 2022/10/26 23:18:02 kettenis Exp $ */ 2/* $NetBSD: t_wait.c,v 1.10 2021/07/17 14:03:35 martin Exp $ */ 3 4/*- 5 * Copyright (c) 2016 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Christos Zoulas. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include "macros.h" 34 35#include <sys/wait.h> 36#include <sys/resource.h> 37 38#include <errno.h> 39#include <inttypes.h> 40#include <limits.h> 41#include <pwd.h> 42#include <signal.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <unistd.h> 46 47#include "atf-c.h" 48 49ATF_TC(waitid_invalid); 50ATF_TC_HEAD(waitid_invalid, tc) 51{ 52 atf_tc_set_md_var(tc, "descr", 53 "Test that waitid(2) returns EINVAL with 0 options"); 54} 55 56ATF_TC_BODY(waitid_invalid, tc) 57{ 58 siginfo_t si; 59 ATF_REQUIRE(waitid(P_ALL, 0, &si, 0) == -1 60 && errno == EINVAL); 61} 62 63ATF_TC(waitid_exited); 64ATF_TC_HEAD(waitid_exited, tc) 65{ 66 atf_tc_set_md_var(tc, "descr", 67 "Test that waitid(2) handled exiting process and code"); 68} 69 70ATF_TC_BODY(waitid_exited, tc) 71{ 72 siginfo_t si; 73 pid_t pid; 74 75 switch (pid = fork()) { 76 case 0: 77 exit(0x5a5a5a5a); 78 /*NOTREACHED*/ 79 case -1: 80 ATF_REQUIRE(pid > 0); 81 __unreachable(); 82 default: 83 ATF_REQUIRE(waitid(P_PID, pid, &si, WEXITED) == 0); 84 ATF_REQUIRE(si.si_status == 0x5a5a5a5a); 85 ATF_REQUIRE(si.si_pid == pid); 86 ATF_REQUIRE(si.si_uid == getuid()); 87 ATF_REQUIRE(si.si_code == CLD_EXITED); 88 printf("user: %ju system: %ju\n", (uintmax_t)si.si_utime, 89 (uintmax_t)si.si_utime); 90 break; 91 } 92} 93 94ATF_TC(waitid_terminated); 95ATF_TC_HEAD(waitid_terminated, tc) 96{ 97 atf_tc_set_md_var(tc, "descr", 98 "Test that waitid(2) handled terminated process and code"); 99} 100 101ATF_TC_BODY(waitid_terminated, tc) 102{ 103 siginfo_t si; 104 pid_t pid; 105 106 switch (pid = fork()) { 107 case 0: 108 sleep(100); 109 /*FALLTHROUGH*/ 110 case -1: 111 ATF_REQUIRE(pid > 0); 112 __unreachable(); 113 default: 114 ATF_REQUIRE(kill(pid, SIGTERM) == 0); 115 ATF_REQUIRE(waitid(P_PID, pid, &si, WEXITED) == 0); 116 ATF_REQUIRE(si.si_status == SIGTERM); 117 ATF_REQUIRE(si.si_pid == pid); 118 ATF_REQUIRE(si.si_uid == getuid()); 119 ATF_REQUIRE(si.si_code == CLD_KILLED); 120 printf("user: %ju system: %ju\n", (uintmax_t)si.si_utime, 121 (uintmax_t)si.si_utime); 122 break; 123 } 124} 125 126ATF_TC(waitid_coredumped); 127ATF_TC_HEAD(waitid_coredumped, tc) 128{ 129 atf_tc_set_md_var(tc, "descr", 130 "Test that waitid(2) handled coredumped process and code"); 131} 132 133ATF_TC_BODY(waitid_coredumped, tc) 134{ 135 siginfo_t si; 136 pid_t pid; 137 static const struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY }; 138 139 switch (pid = fork()) { 140 case 0: 141 ATF_REQUIRE(setrlimit(RLIMIT_CORE, &rl) == 0); 142 *(char *)8 = 0; 143 /*FALLTHROUGH*/ 144 case -1: 145 ATF_REQUIRE(pid > 0); 146 __unreachable(); 147 default: 148 ATF_REQUIRE(waitid(P_PID, pid, &si, WEXITED) == 0); 149 ATF_REQUIRE(si.si_status == SIGSEGV); 150 ATF_REQUIRE(si.si_pid == pid); 151 ATF_REQUIRE(si.si_uid == getuid()); 152 ATF_REQUIRE(si.si_code == CLD_DUMPED); 153 printf("user: %ju system: %ju\n", (uintmax_t)si.si_utime, 154 (uintmax_t)si.si_utime); 155 break; 156 } 157} 158 159ATF_TC(waitid_stop_and_go); 160ATF_TC_HEAD(waitid_stop_and_go, tc) 161{ 162 atf_tc_set_md_var(tc, "descr", 163 "Test that waitid(2) handled stopped/continued process and code"); 164} 165 166ATF_TC_BODY(waitid_stop_and_go, tc) 167{ 168 siginfo_t si; 169 pid_t pid; 170 static const struct rlimit rl = { 0, 0 }; 171 172 ATF_REQUIRE(setrlimit(RLIMIT_CORE, &rl) == 0); 173 switch (pid = fork()) { 174 case 0: 175 sleep(100); 176 /*FALLTHROUGH*/ 177 case -1: 178 ATF_REQUIRE(pid > 0); 179 __unreachable(); 180 default: 181 ATF_REQUIRE(kill(pid, SIGSTOP) == 0); 182 ATF_REQUIRE(waitid(P_PID, pid, &si, WSTOPPED) == 0); 183 ATF_REQUIRE(si.si_status == SIGSTOP); 184 ATF_REQUIRE(si.si_pid == pid); 185 ATF_REQUIRE(si.si_uid == getuid()); 186 ATF_REQUIRE(si.si_code == CLD_STOPPED); 187 printf("user: %ju system: %ju\n", (uintmax_t)si.si_utime, 188 (uintmax_t)si.si_utime); 189 190 ATF_REQUIRE(kill(pid, SIGCONT) == 0); 191 ATF_REQUIRE(waitid(P_PID, pid, &si, WCONTINUED) == 0); 192 ATF_REQUIRE(si.si_status == SIGCONT); 193 ATF_REQUIRE(si.si_pid == pid); 194 ATF_REQUIRE(si.si_uid == getuid()); 195 ATF_REQUIRE(si.si_code == CLD_CONTINUED); 196 printf("user: %ju system: %ju\n", (uintmax_t)si.si_utime, 197 (uintmax_t)si.si_utime); 198 199 ATF_REQUIRE(kill(pid, SIGQUIT) == 0); 200 ATF_REQUIRE(waitid(P_PID, pid, &si, WEXITED) == 0); 201 ATF_REQUIRE(si.si_status == SIGQUIT); 202 ATF_REQUIRE(si.si_pid == pid); 203 ATF_REQUIRE(si.si_uid == getuid()); 204 ATF_REQUIRE(si.si_code == CLD_KILLED); 205 printf("user: %ju system: %ju\n", (uintmax_t)si.si_utime, 206 (uintmax_t)si.si_utime); 207 break; 208 } 209} 210 211ATF_TC(waitid_stopgo_loop); 212ATF_TC_HEAD(waitid_stopgo_loop, tc) 213{ 214 atf_tc_set_md_var(tc, "descr", 215 "Test that waitid(2) handled stopped/continued process loop"); 216} 217 218ATF_TC_BODY(waitid_stopgo_loop, tc) 219{ 220 siginfo_t si; 221 pid_t pid; 222 static const struct rlimit rl = { 0, 0 }; 223 size_t N = 100; 224 225 ATF_REQUIRE(setrlimit(RLIMIT_CORE, &rl) == 0); 226 switch (pid = fork()) { 227 case 0: 228 sleep(100); 229 /*FALLTHROUGH*/ 230 case -1: 231 ATF_REQUIRE(pid > 0); 232 __unreachable(); 233 } 234 235 printf("Before loop of SIGSTOP/SIGCONT sequence %zu times\n", N); 236 while (N --> 0) { 237 ATF_REQUIRE(kill(pid, SIGSTOP) == 0); 238 ATF_REQUIRE(waitid(P_PID, pid, &si, WSTOPPED) == 0); 239 ATF_REQUIRE(si.si_status == SIGSTOP); 240 ATF_REQUIRE(si.si_pid == pid); 241 ATF_REQUIRE(si.si_uid == getuid()); 242 ATF_REQUIRE(si.si_code == CLD_STOPPED); 243 244 ATF_REQUIRE(kill(pid, SIGCONT) == 0); 245 ATF_REQUIRE(waitid(P_PID, pid, &si, WCONTINUED) == 0); 246 ATF_REQUIRE(si.si_status == SIGCONT); 247 ATF_REQUIRE(si.si_pid == pid); 248 ATF_REQUIRE(si.si_uid == getuid()); 249 ATF_REQUIRE(si.si_code == CLD_CONTINUED); 250 } 251 ATF_REQUIRE(kill(pid, SIGQUIT) == 0); 252 ATF_REQUIRE(waitid(P_PID, pid, &si, WEXITED) == 0); 253 ATF_REQUIRE(si.si_status == SIGQUIT); 254 ATF_REQUIRE(si.si_pid == pid); 255 ATF_REQUIRE(si.si_uid == getuid()); 256 ATF_REQUIRE(si.si_code == CLD_KILLED); 257 printf("user: %ju system: %ju\n", (uintmax_t)si.si_utime, 258 (uintmax_t)si.si_utime); 259} 260 261ATF_TP_ADD_TCS(tp) 262{ 263 264 ATF_TP_ADD_TC(tp, waitid_invalid); 265 ATF_TP_ADD_TC(tp, waitid_exited); 266 ATF_TP_ADD_TC(tp, waitid_terminated); 267 ATF_TP_ADD_TC(tp, waitid_coredumped); 268 ATF_TP_ADD_TC(tp, waitid_stop_and_go); 269 ATF_TP_ADD_TC(tp, waitid_stopgo_loop); 270 271 return atf_no_error(); 272} 273