1/* 2 * Check decoding of wait4 syscall. 3 * 4 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@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 <unistd.h> 35#include <sys/wait.h> 36#include <sys/resource.h> 37 38static const char * 39sprint_rusage(const struct rusage *const ru) 40{ 41 static char buf[1024]; 42 snprintf(buf, sizeof(buf), 43 "{ru_utime={tv_sec=%lu, tv_usec=%lu}" 44 ", ru_stime={tv_sec=%lu, tv_usec=%lu}" 45#if VERBOSE 46 ", ru_maxrss=%lu" 47 ", ru_ixrss=%lu" 48 ", ru_idrss=%lu" 49 ", ru_isrss=%lu" 50 ", ru_minflt=%lu" 51 ", ru_majflt=%lu" 52 ", ru_nswap=%lu" 53 ", ru_inblock=%lu" 54 ", ru_oublock=%lu" 55 ", ru_msgsnd=%lu" 56 ", ru_msgrcv=%lu" 57 ", ru_nsignals=%lu" 58 ", ru_nvcsw=%lu" 59 ", ru_nivcsw=%lu}" 60#else 61 ", ...}" 62#endif 63 , (long) ru->ru_utime.tv_sec 64 , (long) ru->ru_utime.tv_usec 65 , (long) ru->ru_stime.tv_sec 66 , (long) ru->ru_stime.tv_usec 67#if VERBOSE 68 , (long) ru->ru_maxrss 69 , (long) ru->ru_ixrss 70 , (long) ru->ru_idrss 71 , (long) ru->ru_isrss 72 , (long) ru->ru_minflt 73 , (long) ru->ru_majflt 74 , (long) ru->ru_nswap 75 , (long) ru->ru_inblock 76 , (long) ru->ru_oublock 77 , (long) ru->ru_msgsnd 78 , (long) ru->ru_msgrcv 79 , (long) ru->ru_nsignals 80 , (long) ru->ru_nvcsw 81 , (long) ru->ru_nivcsw 82#endif 83 ); 84 return buf; 85} 86 87static pid_t 88do_wait4(pid_t pid, int *wstatus, int options, struct rusage *ru) 89{ 90 sigset_t mask = {}; 91 sigaddset(&mask, SIGCHLD); 92 93 assert(sigprocmask(SIG_BLOCK, &mask, NULL) == 0); 94 pid_t rc = wait4(pid, wstatus, options, ru); 95 assert(sigprocmask(SIG_UNBLOCK, &mask, NULL) == 0); 96 return rc; 97} 98 99int 100main(void) 101{ 102 tprintf("%s", ""); 103 104 int fds[2]; 105 if (pipe(fds)) 106 perror_msg_and_fail("pipe"); 107 108 pid_t pid; 109 pid = fork(); 110 if (pid < 0) 111 perror_msg_and_fail("fork"); 112 113 if (!pid) { 114 char c; 115 (void) close(1); 116 assert(read(0, &c, sizeof(c)) == 1); 117 return 42; 118 } 119 120 (void) close(0); 121 122 int *const s = tail_alloc(sizeof(*s)); 123 if (wait4(pid, s, WNOHANG|__WALL, NULL)) 124 perror_msg_and_fail("wait4 #1"); 125 tprintf("wait4(%d, %p, WNOHANG|__WALL, NULL) = 0\n", pid, s); 126 127 struct rusage *const rusage = tail_alloc(sizeof(*rusage)); 128 if (wait4(pid, s, WNOHANG|__WALL, rusage)) 129 perror_msg_and_fail("wait4 #2"); 130 tprintf("wait4(%d, %p, WNOHANG|__WALL, %p) = 0\n", pid, s, rusage); 131 132 assert(write(1, "", 1) == 1); 133 (void) close(1); 134 135 assert(do_wait4(pid, s, 0, rusage) == pid); 136 assert(WIFEXITED(*s) && WEXITSTATUS(*s) == 42); 137 tprintf("wait4(%d, [{WIFEXITED(s) && WEXITSTATUS(s) == 42}], 0, %s)" 138 " = %d\n", pid, sprint_rusage(rusage), pid); 139 140 pid = fork(); 141 if (pid < 0) 142 perror_msg_and_fail("fork"); 143 144 if (!pid) { 145 (void) raise(SIGUSR1); 146 return 1; 147 } 148 149 assert(do_wait4(pid, s, __WALL, rusage) == pid); 150 assert(WIFSIGNALED(*s) && WTERMSIG(*s) == SIGUSR1); 151 tprintf("wait4(%d, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGUSR1}]" 152 ", __WALL, %s) = %d\n", pid, sprint_rusage(rusage), pid); 153 154 if (pipe(fds)) 155 perror_msg_and_fail("pipe"); 156 pid = fork(); 157 if (pid < 0) 158 perror_msg_and_fail("fork"); 159 160 if (!pid) { 161 (void) close(1); 162 raise(SIGSTOP); 163 char c; 164 assert(read(0, &c, sizeof(c)) == 1); 165 return 0; 166 } 167 168 (void) close(0); 169 170 assert(do_wait4(pid, s, WSTOPPED, rusage) == pid); 171 assert(WIFSTOPPED(*s) && WSTOPSIG(*s) == SIGSTOP); 172 tprintf("wait4(%d, [{WIFSTOPPED(s) && WSTOPSIG(s) == SIGSTOP}]" 173 ", WSTOPPED, %s) = %d\n", pid, sprint_rusage(rusage), pid); 174 175 if (kill(pid, SIGCONT)) 176 perror_msg_and_fail("kill(SIGCONT)"); 177 178#if defined WCONTINUED && defined WIFCONTINUED 179 assert(do_wait4(pid, s, WCONTINUED, rusage) == pid); 180 assert(WIFCONTINUED(*s)); 181 tprintf("wait4(%d, [{WIFCONTINUED(s)}], WCONTINUED" 182 ", %s) = %d\n", pid, sprint_rusage(rusage), pid); 183#endif /* WCONTINUED && WIFCONTINUED */ 184 185 assert(write(1, "", 1) == 1); 186 (void) close(1); 187 188 assert(do_wait4(pid, s, 0, rusage) == pid); 189 assert(WIFEXITED(*s) && WEXITSTATUS(*s) == 0); 190 tprintf("wait4(%d, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0" 191 ", %s) = %d\n", pid, sprint_rusage(rusage), pid); 192 193 assert(wait4(-1, s, WNOHANG|WSTOPPED|__WALL, rusage) == -1); 194 tprintf("wait4(-1, %p, WNOHANG|WSTOPPED|__WALL, %p) = -1 %s (%m)\n", 195 s, rusage, errno2name()); 196 197 tprintf("%s\n", "+++ exited with 0 +++"); 198 return 0; 199} 200