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