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 (at) in.ibm.com> */ 39 /******************************************************************************/ 40 41 #define _XOPEN_SOURCE 500 42 #include <stdio.h> 43 #include <errno.h> 44 #include <stdlib.h> 45 #include <sys/wait.h> 46 #include <sys/types.h> 47 #include <unistd.h> 48 #include <sys/stat.h> 49 50 #include "test.h" 51 #include "safe_macros.h" 52 #include "lapi/syscalls.h" 53 54 struct testcase_t { 55 const char *msg; 56 idtype_t idtype; 57 id_t id; 58 pid_t child; 59 int options; 60 int exp_ret; 61 int exp_errno; 62 void (*setup) (struct testcase_t *); 63 void (*cleanup) (struct testcase_t *); 64 }; 65 66 static void setup(void); 67 static void cleanup(void); 68 69 static void setup2(struct testcase_t *); 70 static void setup3(struct testcase_t *); 71 static void setup4(struct testcase_t *); 72 static void setup5(struct testcase_t *); 73 static void setup6(struct testcase_t *); 74 static void cleanup2(struct testcase_t *); 75 static void cleanup5(struct testcase_t *); 76 static void cleanup6(struct testcase_t *); 77 78 struct testcase_t tdat[] = { 79 { 80 .msg = "WNOHANG", 81 .idtype = P_ALL, 82 .id = 0, 83 .options = WNOHANG, 84 .exp_ret = -1, 85 .exp_errno = EINVAL, 86 }, 87 { 88 .msg = "WNOHANG | WEXITED no child", 89 .idtype = P_ALL, 90 .id = 0, 91 .options = WNOHANG | WEXITED, 92 .exp_ret = -1, 93 .exp_errno = ECHILD, 94 }, 95 { 96 .msg = "WNOHANG | WEXITED with child", 97 .idtype = P_ALL, 98 .id = 0, 99 .options = WNOHANG | WEXITED, 100 .exp_ret = 0, 101 .setup = setup2, 102 .cleanup = cleanup2 103 }, 104 { 105 .msg = "P_PGID, WEXITED wait for child", 106 .idtype = P_PGID, 107 .options = WEXITED, 108 .exp_ret = 0, 109 .setup = setup3, 110 }, 111 { 112 .msg = "P_PID, WEXITED wait for child", 113 .idtype = P_PID, 114 .options = WEXITED, 115 .exp_ret = 0, 116 .setup = setup4, 117 }, 118 { 119 .msg = "P_PID, WSTOPPED | WNOWAIT", 120 .idtype = P_PID, 121 .options = WSTOPPED | WNOWAIT, 122 .exp_ret = 0, 123 .setup = setup5, 124 .cleanup = cleanup5 125 }, 126 { 127 .msg = "P_PID, WCONTINUED", 128 .idtype = P_PID, 129 .options = WCONTINUED, 130 .exp_ret = 0, 131 .setup = setup6, 132 .cleanup = cleanup6 133 }, 134 { 135 .msg = "P_PID, WEXITED not a child of the calling process", 136 .idtype = P_PID, 137 .id = 1, 138 .options = WEXITED, 139 .exp_ret = -1, 140 .exp_errno = ECHILD, 141 .setup = setup2, 142 .cleanup = cleanup2 143 }, 144 145 }; 146 147 char *TCID = "waitid02"; 148 static int TST_TOTAL = ARRAY_SIZE(tdat); 149 150 static void makechild(struct testcase_t *t, void (*childfn)(void)) 151 { 152 t->child = fork(); 153 switch (t->child) { 154 case -1: 155 tst_brkm(TBROK | TERRNO, cleanup, "fork"); 156 break; 157 case 0: 158 childfn(); 159 exit(0); 160 } 161 } 162 163 static void wait4child(pid_t pid) 164 { 165 int status; 166 SAFE_WAITPID(cleanup, pid, &status, 0); 167 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 168 tst_resm(TFAIL, "child returns %d", status); 169 } 170 171 static void dummy_child(void) 172 { 173 } 174 175 static void waiting_child(void) 176 { 177 TST_SAFE_CHECKPOINT_WAIT(NULL, 0); 178 } 179 180 static void stopped_child(void) 181 { 182 kill(getpid(), SIGSTOP); 183 TST_SAFE_CHECKPOINT_WAIT(NULL, 0); 184 } 185 186 static void setup2(struct testcase_t *t) 187 { 188 makechild(t, waiting_child); 189 } 190 191 static void cleanup2(struct testcase_t *t) 192 { 193 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); 194 wait4child(t->child); 195 } 196 197 static void setup3(struct testcase_t *t) 198 { 199 t->id = getpgid(0); 200 makechild(t, dummy_child); 201 } 202 203 static void setup4(struct testcase_t *t) 204 { 205 makechild(t, dummy_child); 206 t->id = t->child; 207 } 208 209 static void setup5(struct testcase_t *t) 210 { 211 makechild(t, stopped_child); 212 t->id = t->child; 213 } 214 215 static void cleanup5(struct testcase_t *t) 216 { 217 kill(t->child, SIGCONT); 218 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); 219 wait4child(t->child); 220 } 221 222 static void setup6(struct testcase_t *t) 223 { 224 siginfo_t infop; 225 makechild(t, stopped_child); 226 t->id = t->child; 227 if (waitid(P_PID, t->child, &infop, WSTOPPED) != 0) 228 tst_brkm(TBROK | TERRNO, cleanup, "waitpid setup6"); 229 kill(t->child, SIGCONT); 230 } 231 232 static void cleanup6(struct testcase_t *t) 233 { 234 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); 235 wait4child(t->child); 236 } 237 238 static void setup(void) 239 { 240 TEST_PAUSE; 241 tst_tmpdir(); 242 TST_CHECKPOINT_INIT(tst_rmdir); 243 } 244 245 static void cleanup(void) 246 { 247 tst_rmdir(); 248 tst_exit(); 249 } 250 251 static void test_waitid(struct testcase_t *t) 252 { 253 siginfo_t infop; 254 255 if (t->setup) 256 t->setup(t); 257 258 tst_resm(TINFO, "%s", t->msg); 259 tst_resm(TINFO, "(%d) waitid(%d, %d, %p, %d)", getpid(), t->idtype, 260 t->id, &infop, t->options); 261 memset(&infop, 0, sizeof(infop)); 262 263 TEST(waitid(t->idtype, t->id, &infop, t->options)); 264 if (TEST_RETURN == t->exp_ret) { 265 if (TEST_RETURN == -1) { 266 if (TEST_ERRNO == t->exp_errno) 267 tst_resm(TPASS, "exp_errno=%d", t->exp_errno); 268 else 269 tst_resm(TFAIL|TTERRNO, "exp_errno=%d", 270 t->exp_errno); 271 } else { 272 tst_resm(TPASS, "ret: %d", t->exp_ret); 273 } 274 } else { 275 tst_resm(TFAIL|TTERRNO, "ret=%ld expected=%d", 276 TEST_RETURN, t->exp_ret); 277 } 278 tst_resm(TINFO, "si_pid = %d ; si_code = %d ; si_status = %d", 279 infop.si_pid, infop.si_code, 280 infop.si_status); 281 282 if (t->cleanup) 283 t->cleanup(t); 284 } 285 286 int main(int ac, char **av) 287 { 288 int lc, testno; 289 290 tst_parse_opts(ac, av, NULL, NULL); 291 292 setup(); 293 for (lc = 0; TEST_LOOPING(lc); ++lc) { 294 tst_count = 0; 295 for (testno = 0; testno < TST_TOTAL; testno++) 296 test_waitid(&tdat[testno]); 297 } 298 cleanup(); 299 tst_exit(); 300 } 301