1/******************************************************************************/ 2/* Copyright (c) Crackerjack Project., 2007 */ 3/* */ 4/* This program is free software; you can redistribute it and/or modify */ 5/* it under the terms of the GNU General Public License as published by */ 6/* the Free Software Foundation; either version 2 of the License, or */ 7/* (at your option) any later version. */ 8/* */ 9/* This program is distributed in the hope that it will be useful, */ 10/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 11/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ 12/* the GNU General Public License for more details. */ 13/* */ 14/* You should have received a copy of the GNU General Public License along */ 15/* with this program; if not, write to the Free Software Foundation, Inc., */ 16/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 17/* */ 18/******************************************************************************/ 19/******************************************************************************/ 20/* */ 21/* File: waitid02.c */ 22/* */ 23/* Description: This tests the waitid() syscall */ 24/* */ 25/* Usage: <for command-line> */ 26/* waitid02 [-c n] [-e][-i n] [-I x] [-p x] [-t] */ 27/* where, -c n : Run n copies concurrently. */ 28/* -e : Turn on errno logging. */ 29/* -i n : Execute test n times. */ 30/* -I x : Execute test for x seconds. */ 31/* -P x : Pause for x seconds between iterations. */ 32/* -t : Turn on syscall timing. */ 33/* */ 34/* Total Tests: 1 */ 35/* */ 36/* Test Name: waitid02 */ 37/* History: Porting from Crackerjack to LTP is done by */ 38/* Manas Kumar Nayak maknayak@in.ibm.com> */ 39/******************************************************************************/ 40 41#include <stdio.h> 42#include <errno.h> 43#include <stdlib.h> 44#include <sys/wait.h> 45#include <sys/types.h> 46#include <unistd.h> 47#include <sys/stat.h> 48 49#include "test.h" 50#include "linux_syscall_numbers.h" 51 52struct testcase_t { 53 const char *msg; 54 idtype_t idtype; 55 id_t id; 56 pid_t child; 57 int options; 58 int exp_ret; 59 int exp_errno; 60 void (*setup) (struct testcase_t *); 61 void (*cleanup) (struct testcase_t *); 62}; 63 64static void setup(void); 65static void cleanup(void); 66 67static void setup2(struct testcase_t *); 68static void setup3(struct testcase_t *); 69static void setup4(struct testcase_t *); 70static void setup5(struct testcase_t *); 71static void setup6(struct testcase_t *); 72static void cleanup2(struct testcase_t *); 73static void cleanup5(struct testcase_t *); 74static void cleanup6(struct testcase_t *); 75 76struct testcase_t tdat[] = { 77 { 78 .msg = "WNOHANG", 79 .idtype = P_ALL, 80 .id = 0, 81 .options = WNOHANG, 82 .exp_ret = -1, 83 .exp_errno = EINVAL, 84 }, 85 { 86 .msg = "WNOHANG | WEXITED no child", 87 .idtype = P_ALL, 88 .id = 0, 89 .options = WNOHANG | WEXITED, 90 .exp_ret = -1, 91 .exp_errno = ECHILD, 92 }, 93 { 94 .msg = "WNOHANG | WEXITED with child", 95 .idtype = P_ALL, 96 .id = 0, 97 .options = WNOHANG | WEXITED, 98 .exp_ret = 0, 99 .setup = setup2, 100 .cleanup = cleanup2 101 }, 102 { 103 .msg = "P_PGID, WEXITED wait for child", 104 .idtype = P_PGID, 105 .options = WEXITED, 106 .exp_ret = 0, 107 .setup = setup3, 108 }, 109 { 110 .msg = "P_PID, WEXITED wait for child", 111 .idtype = P_PID, 112 .options = WEXITED, 113 .exp_ret = 0, 114 .setup = setup4, 115 }, 116 { 117 .msg = "P_PID, WSTOPPED | WNOWAIT", 118 .idtype = P_PID, 119 .options = WSTOPPED | WNOWAIT, 120 .exp_ret = 0, 121 .setup = setup5, 122 .cleanup = cleanup5 123 }, 124 { 125 .msg = "P_PID, WCONTINUED", 126 .idtype = P_PID, 127 .options = WCONTINUED, 128 .exp_ret = 0, 129 .setup = setup6, 130 .cleanup = cleanup6 131 }, 132 { 133 .msg = "P_PID, WEXITED not a child of the calling process", 134 .idtype = P_PID, 135 .id = 1, 136 .options = WEXITED, 137 .exp_ret = -1, 138 .exp_errno = ECHILD, 139 .setup = setup2, 140 .cleanup = cleanup2 141 }, 142 143}; 144 145char *TCID = "waitid02"; 146static int TST_TOTAL = ARRAY_SIZE(tdat); 147 148static void makechild(struct testcase_t *t, void (*childfn)(void)) 149{ 150 t->child = fork(); 151 switch (t->child) { 152 case -1: 153 tst_brkm(TBROK | TERRNO, cleanup, "fork"); 154 break; 155 case 0: 156 childfn(); 157 exit(0); 158 } 159} 160 161static void wait4child(pid_t pid) 162{ 163 int status; 164 if (waitpid(pid, &status, 0) == -1) 165 tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); 166 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 167 tst_resm(TFAIL, "child returns %d", status); 168} 169 170static void dummy_child(void) 171{ 172} 173 174static void waiting_child(void) 175{ 176 TST_SAFE_CHECKPOINT_WAIT(NULL, 0); 177} 178 179static void stopped_child(void) 180{ 181 kill(getpid(), SIGSTOP); 182 TST_SAFE_CHECKPOINT_WAIT(NULL, 0); 183} 184 185static void setup2(struct testcase_t *t) 186{ 187 makechild(t, waiting_child); 188} 189 190static void cleanup2(struct testcase_t *t) 191{ 192 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); 193 wait4child(t->child); 194} 195 196static void setup3(struct testcase_t *t) 197{ 198 t->id = getpgid(0); 199 makechild(t, dummy_child); 200} 201 202static void setup4(struct testcase_t *t) 203{ 204 makechild(t, dummy_child); 205 t->id = t->child; 206} 207 208static void setup5(struct testcase_t *t) 209{ 210 makechild(t, stopped_child); 211 t->id = t->child; 212} 213 214static void cleanup5(struct testcase_t *t) 215{ 216 kill(t->child, SIGCONT); 217 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); 218 wait4child(t->child); 219} 220 221static void setup6(struct testcase_t *t) 222{ 223 siginfo_t infop; 224 makechild(t, stopped_child); 225 t->id = t->child; 226 if (waitid(P_PID, t->child, &infop, WSTOPPED) != 0) 227 tst_brkm(TBROK | TERRNO, cleanup, "waitpid setup6"); 228 kill(t->child, SIGCONT); 229} 230 231static void cleanup6(struct testcase_t *t) 232{ 233 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); 234 wait4child(t->child); 235} 236 237static void setup(void) 238{ 239 TEST_PAUSE; 240 tst_tmpdir(); 241 TST_CHECKPOINT_INIT(tst_rmdir); 242} 243 244static void cleanup(void) 245{ 246 tst_rmdir(); 247 tst_exit(); 248} 249 250static void test_waitid(struct testcase_t *t) 251{ 252 siginfo_t infop; 253 254 if (t->setup) 255 t->setup(t); 256 257 tst_resm(TINFO, "%s", t->msg); 258 tst_resm(TINFO, "(%d) waitid(%d, %d, %p, %d)", getpid(), t->idtype, 259 t->id, &infop, t->options); 260 memset(&infop, 0, sizeof(infop)); 261 262 TEST(waitid(t->idtype, t->id, &infop, t->options)); 263 if (TEST_RETURN == t->exp_ret) { 264 if (TEST_RETURN == -1) { 265 if (TEST_ERRNO == t->exp_errno) 266 tst_resm(TPASS, "exp_errno=%d", t->exp_errno); 267 else 268 tst_resm(TFAIL|TTERRNO, "exp_errno=%d", 269 t->exp_errno); 270 } else { 271 tst_resm(TPASS, "ret: %d", t->exp_ret); 272 } 273 } else { 274 tst_resm(TFAIL|TTERRNO, "ret=%ld expected=%d", 275 TEST_RETURN, t->exp_ret); 276 } 277 tst_resm(TINFO, "si_pid = %d ; si_code = %d ; si_status = %d", 278 infop.si_pid, infop.si_code, 279 infop.si_status); 280 281 if (t->cleanup) 282 t->cleanup(t); 283} 284 285int main(int ac, char **av) 286{ 287 int lc, testno; 288 289 tst_parse_opts(ac, av, NULL, NULL); 290 291 setup(); 292 for (lc = 0; TEST_LOOPING(lc); ++lc) { 293 tst_count = 0; 294 for (testno = 0; testno < TST_TOTAL; testno++) 295 test_waitid(&tdat[testno]); 296 } 297 cleanup(); 298 tst_exit(); 299} 300