1/* 2 * Check decoding of waitid syscall. 3 * 4 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@altlinux.org> 5 * Copyright (c) 2016-2017 The strace developers. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "tests.h" 32#include <assert.h> 33#include <signal.h> 34#include <stdio.h> 35#include <string.h> 36#include <unistd.h> 37#include <sys/wait.h> 38#include <sys/resource.h> 39#include <asm/unistd.h> 40 41static const char * 42sprint_rusage(const struct rusage *const ru) 43{ 44 static char buf[1024]; 45 snprintf(buf, sizeof(buf), 46 "{ru_utime={tv_sec=%lld, tv_usec=%llu}" 47 ", ru_stime={tv_sec=%lld, tv_usec=%llu}" 48#if VERBOSE 49 ", ru_maxrss=%llu" 50 ", ru_ixrss=%llu" 51 ", ru_idrss=%llu" 52 ", ru_isrss=%llu" 53 ", ru_minflt=%llu" 54 ", ru_majflt=%llu" 55 ", ru_nswap=%llu" 56 ", ru_inblock=%llu" 57 ", ru_oublock=%llu" 58 ", ru_msgsnd=%llu" 59 ", ru_msgrcv=%llu" 60 ", ru_nsignals=%llu" 61 ", ru_nvcsw=%llu" 62 ", ru_nivcsw=%llu}" 63#else 64 ", ...}" 65#endif 66 , (long long) ru->ru_utime.tv_sec 67 , zero_extend_signed_to_ull(ru->ru_utime.tv_usec) 68 , (long long) ru->ru_stime.tv_sec 69 , zero_extend_signed_to_ull(ru->ru_stime.tv_usec) 70#if VERBOSE 71 , zero_extend_signed_to_ull(ru->ru_maxrss) 72 , zero_extend_signed_to_ull(ru->ru_ixrss) 73 , zero_extend_signed_to_ull(ru->ru_idrss) 74 , zero_extend_signed_to_ull(ru->ru_isrss) 75 , zero_extend_signed_to_ull(ru->ru_minflt) 76 , zero_extend_signed_to_ull(ru->ru_majflt) 77 , zero_extend_signed_to_ull(ru->ru_nswap) 78 , zero_extend_signed_to_ull(ru->ru_inblock) 79 , zero_extend_signed_to_ull(ru->ru_oublock) 80 , zero_extend_signed_to_ull(ru->ru_msgsnd) 81 , zero_extend_signed_to_ull(ru->ru_msgrcv) 82 , zero_extend_signed_to_ull(ru->ru_nsignals) 83 , zero_extend_signed_to_ull(ru->ru_nvcsw) 84 , zero_extend_signed_to_ull(ru->ru_nivcsw) 85#endif 86 ); 87 return buf; 88} 89 90#define CASE(x) case x: return #x 91 92static const char * 93si_code_2_name(const int code) 94{ 95 switch (code) { 96#ifdef CLD_EXITED 97 CASE(CLD_EXITED); 98#endif 99#ifdef CLD_KILLED 100 CASE(CLD_KILLED); 101#endif 102#ifdef CLD_DUMPED 103 CASE(CLD_DUMPED); 104#endif 105#ifdef CLD_TRAPPED 106 CASE(CLD_TRAPPED); 107#endif 108#ifdef CLD_STOPPED 109 CASE(CLD_STOPPED); 110#endif 111#ifdef CLD_CONTINUED 112 CASE(CLD_CONTINUED); 113#endif 114 default: 115 perror_msg_and_fail("unknown si_code %d", code); 116 } 117} 118 119static const char * 120sprint_siginfo(const siginfo_t *const si, const char *const status_text) 121{ 122 static char buf[1024]; 123 snprintf(buf, sizeof(buf), 124 "{si_signo=SIGCHLD" 125 ", si_code=%s" 126 ", si_pid=%u" 127 ", si_uid=%u" 128 ", si_status=%s" 129 ", si_utime=%llu" 130 ", si_stime=%llu}", 131 si_code_2_name(si->si_code), 132 si->si_pid, 133 si->si_uid, 134 status_text, 135 zero_extend_signed_to_ull(si->si_utime), 136 zero_extend_signed_to_ull(si->si_stime)); 137 return buf; 138} 139 140static unsigned long 141poison(unsigned int v) 142{ 143 return (unsigned long) 0xfacefeed00000000ULL | v; 144} 145 146static long 147do_waitid(const unsigned int idtype, 148 const unsigned int id, 149 const siginfo_t *const infop, 150 const unsigned int options, 151 const struct rusage *const rusage) 152{ 153 sigset_t mask = {}; 154 sigaddset(&mask, SIGCHLD); 155 156 assert(sigprocmask(SIG_BLOCK, &mask, NULL) == 0); 157 long rc = syscall(__NR_waitid, poison(idtype), poison(id), 158 infop, poison(options), rusage); 159 assert(sigprocmask(SIG_UNBLOCK, &mask, NULL) == 0); 160 return rc; 161} 162 163int 164main(void) 165{ 166 tprintf("%s", ""); 167 168 int fds[2]; 169 if (pipe(fds)) 170 perror_msg_and_fail("pipe"); 171 172 pid_t pid; 173 pid = fork(); 174 if (pid < 0) 175 perror_msg_and_fail("fork"); 176 177 if (!pid) { 178 char c; 179 (void) close(1); 180 assert(read(0, &c, sizeof(c)) == 1); 181 return 42; 182 } 183 184 (void) close(0); 185 186 if (do_waitid(P_PID, pid, 0, WNOHANG|WEXITED, 0)) 187 perror_msg_and_fail("waitid #1"); 188 tprintf("waitid(P_PID, %d, NULL, WNOHANG|WEXITED, NULL) = 0\n", pid); 189 190 TAIL_ALLOC_OBJECT_CONST_PTR(siginfo_t, sinfo); 191 memset(sinfo, 0, sizeof(*sinfo)); 192 TAIL_ALLOC_OBJECT_CONST_PTR(struct rusage, rusage); 193 if (do_waitid(P_PID, pid, sinfo, WNOHANG|WEXITED|WSTOPPED, rusage)) 194 perror_msg_and_fail("waitid #2"); 195 tprintf("waitid(P_PID, %d, {}, WNOHANG|WEXITED|WSTOPPED, %s) = 0\n", 196 pid, sprint_rusage(rusage)); 197 198 assert(write(1, "", 1) == 1); 199 (void) close(1); 200 201 if (do_waitid(P_PID, pid, sinfo, WEXITED, rusage)) 202 perror_msg_and_fail("waitid #3"); 203 tprintf("waitid(P_PID, %d, %s, WEXITED, %s) = 0\n", 204 pid, sprint_siginfo(sinfo, "42"), sprint_rusage(rusage)); 205 206 pid = fork(); 207 if (pid < 0) 208 perror_msg_and_fail("fork"); 209 210 if (!pid) { 211 (void) raise(SIGUSR1); 212 return 1; 213 } 214 215 if (do_waitid(P_PID, pid, sinfo, WEXITED, rusage)) 216 perror_msg_and_fail("waitid #4"); 217 tprintf("waitid(P_PID, %d, %s, WEXITED, %s) = 0\n", 218 pid, sprint_siginfo(sinfo, "SIGUSR1"), sprint_rusage(rusage)); 219 220 if (pipe(fds)) 221 perror_msg_and_fail("pipe"); 222 pid = fork(); 223 if (pid < 0) 224 perror_msg_and_fail("fork"); 225 226 if (!pid) { 227 (void) close(1); 228 raise(SIGSTOP); 229 char c; 230 assert(read(0, &c, sizeof(c)) == 1); 231 return 0; 232 } 233 234 (void) close(0); 235 236 if (do_waitid(P_PID, pid, sinfo, WSTOPPED, rusage)) 237 perror_msg_and_fail("waitid #5"); 238 tprintf("waitid(P_PID, %d, %s, WSTOPPED, %s) = 0\n", 239 pid, sprint_siginfo(sinfo, "SIGSTOP"), sprint_rusage(rusage)); 240 241 if (kill(pid, SIGCONT)) 242 perror_msg_and_fail("kill(SIGCONT)"); 243 244#if defined WCONTINUED 245 if (do_waitid(P_PID, pid, sinfo, WCONTINUED, rusage)) 246 perror_msg_and_fail("waitid #6"); 247 tprintf("waitid(P_PID, %d, %s, WCONTINUED, %s) = 0\n", 248 pid, sprint_siginfo(sinfo, "SIGCONT"), sprint_rusage(rusage)); 249#endif /* WCONTINUED */ 250 251 assert(write(1, "", 1) == 1); 252 (void) close(1); 253 254 if (do_waitid(P_PID, pid, sinfo, WEXITED, rusage)) 255 perror_msg_and_fail("waitid #7"); 256 tprintf("waitid(P_PID, %d, %s, WEXITED, %s) = 0\n", 257 pid, sprint_siginfo(sinfo, "0"), sprint_rusage(rusage)); 258 259 long rc = do_waitid(P_ALL, -1, sinfo, WEXITED|WSTOPPED, rusage); 260 tprintf("waitid(P_ALL, -1, %p, WEXITED|WSTOPPED, %p)" 261 " = %ld %s (%m)\n", sinfo, rusage, rc, errno2name()); 262 263 tprintf("%s\n", "+++ exited with 0 +++"); 264 return 0; 265} 266