1 /* 2 * 3 * Copyright (c) International Business Machines Corp., 2002 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /* 21 * NAME 22 * pipe04.c 23 * 24 * DESCRIPTION 25 * Check that processes are killable, even when they are still writing 26 * data to a pipe. 27 * 28 * ALGORITHM 29 * 1. Open a pipe 30 * 2. fork a two children that will write to the pipe 31 * 3. read a bit from both children 32 * 3. kill both children and wait to make sure they die 33 * 34 * USAGE: <for command-line> 35 * pipe04 [-c n] [-f] [-i n] [-I x] [-P x] [-t] 36 * where, -c n : Run n copies concurrently. 37 * -f : Turn off functionality Testing. 38 * -i n : Execute test n times. 39 * -I x : Execute test for x seconds. 40 * -P x : Pause for x seconds between iterations. 41 * -t : Turn on syscall timing. 42 * 43 * HISTORY 44 * 11/2002 Ported by Paul Larson 45 */ 46 #include <unistd.h> 47 #include <errno.h> 48 #include <signal.h> 49 #include <sys/types.h> 50 #include <sys/wait.h> 51 #include "test.h" 52 #include "safe_macros.h" 53 54 char *TCID = "pipe04"; 55 int TST_TOTAL = 1; 56 57 int fildes[2]; /* fds for pipe read and write */ 58 59 void setup(void); 60 void cleanup(void); 61 void c1func(void); 62 void c2func(void); 63 void alarmfunc(int); 64 65 ssize_t do_read(int fd, void *buf, size_t count) 66 { 67 ssize_t n; 68 69 do { 70 n = read(fd, buf, count); 71 } while (n < 0 && errno == EINTR); 72 73 return n; 74 } 75 76 int main(int ac, char **av) 77 { 78 int lc; 79 pid_t c1pid, c2pid; 80 int wtstatus; 81 int bytesread; 82 int acnt = 0, bcnt = 0; 83 84 char rbuf[BUFSIZ]; 85 86 tst_parse_opts(ac, av, NULL, NULL); 87 #ifdef UCLINUX 88 maybe_run_child(&c1func, "ndd", 1, &fildes[0], &fildes[1]); 89 maybe_run_child(&c2func, "ndd", 2, &fildes[0], &fildes[1]); 90 #endif 91 92 setup(); 93 94 for (lc = 0; TEST_LOOPING(lc); lc++) { 95 96 /* reset tst_count in case we are looping */ 97 tst_count = 0; 98 99 SAFE_PIPE(cleanup, fildes); 100 101 if ((c1pid = FORK_OR_VFORK()) == -1) 102 tst_brkm(TBROK, cleanup, "fork() failed - " 103 "errno %d", errno); 104 if (c1pid == 0) 105 #ifdef UCLINUX 106 if (self_exec(av[0], "ndd", 1, fildes[0], fildes[1]) < 107 0) { 108 tst_brkm(TBROK, cleanup, "self_exec failed"); 109 } 110 #else 111 c1func(); 112 #endif 113 if ((c2pid = FORK_OR_VFORK()) == -1) 114 tst_brkm(TBROK, cleanup, "fork() failed - " 115 "errno %d", errno); 116 if (c2pid == 0) 117 #ifdef UCLINUX 118 if (self_exec(av[0], "ndd", 2, fildes[0], fildes[1]) < 119 0) { 120 tst_brkm(TBROK, cleanup, "self_exec failed"); 121 } 122 #else 123 c2func(); 124 #endif 125 126 /* PARENT */ 127 if (close(fildes[1]) == -1) 128 tst_resm(TWARN, "Could not close fildes[1] - errno %d", 129 errno); 130 /* 131 * Read a bit from the children first 132 */ 133 while ((acnt < 100) && (bcnt < 100)) { 134 bytesread = do_read(fildes[0], rbuf, sizeof(rbuf)); 135 if (bytesread < 0) { 136 tst_resm(TFAIL, "Unable to read from pipe, " 137 "errno=%d", errno); 138 break; 139 } 140 switch (rbuf[1]) { 141 case 'A': 142 acnt++; 143 break; 144 case 'b': 145 bcnt++; 146 break; 147 default: 148 tst_resm(TFAIL, "Got bogus '%c' " 149 "character", rbuf[1]); 150 break; 151 } 152 } 153 154 /* 155 * Try to kill the children 156 */ 157 if (kill(c1pid, SIGKILL) == -1) 158 tst_resm(TFAIL, "failed to kill child 1, errno=%d", 159 errno); 160 if (kill(c2pid, SIGKILL) == -1) 161 tst_resm(TFAIL, "failed to kill child 1, errno=%d", 162 errno); 163 164 /* 165 * Set action for the alarm 166 */ 167 if (signal(SIGALRM, alarmfunc) == SIG_ERR) 168 tst_resm(TWARN | TERRNO, "call to signal failed"); 169 /* 170 * Set an alarm for 60 seconds just in case the child 171 * processes don't die 172 */ 173 alarm(60); 174 if (waitpid(c1pid, &wtstatus, 0) != -1) { 175 if (wtstatus != SIGKILL) 176 tst_resm(TFAIL | TERRNO, 177 "unexpected wait status " "%d", 178 wtstatus); 179 else 180 tst_resm(TPASS, "Child 1 killed while " 181 "writing to a pipe"); 182 } 183 if (waitpid(c2pid, &wtstatus, 0) != -1) { 184 if (!WIFSIGNALED(wtstatus) || 185 WTERMSIG(wtstatus) != SIGKILL) 186 tst_resm(TFAIL | TERRNO, 187 "unexpected wait status " "%d", 188 wtstatus); 189 else 190 tst_resm(TPASS, "Child 2 killed while " 191 "writing to a pipe"); 192 } 193 if (alarm(0) <= 0) 194 tst_resm(TWARN, "call to alarm(0) failed"); 195 } 196 cleanup(); 197 198 tst_exit(); 199 } 200 201 /* 202 * setup() - performs all ONE TIME setup for this test. 203 */ 204 void setup(void) 205 { 206 207 tst_sig(FORK, DEF_HANDLER, cleanup); 208 209 TEST_PAUSE; 210 } 211 212 /* 213 * cleanup() - performs all ONE TIME cleanup for this test at 214 * completion or premature exit. 215 */ 216 void cleanup(void) 217 { 218 } 219 220 void c1func(void) 221 { 222 if (close(fildes[0]) == -1) 223 tst_resm(TWARN, "Could not close fildes[0] - errno %d", errno); 224 while (1) 225 if (write(fildes[1], "bbbbbbbbbbbbbbbbbbbbbbbbb", 25) == -1) 226 tst_resm(TBROK | TERRNO, "[child 1] pipe write failed"); 227 } 228 229 void c2func(void) 230 { 231 if (close(fildes[0]) == -1) 232 tst_resm(TWARN, "Could not close fildes[0] - errno %d", errno); 233 while (1) 234 if (write(fildes[1], "AAAAAAAAAAAAAAAAAAAAAAAAA", 25) == -1) 235 tst_resm(TBROK | TERRNO, "[child 2] pipe write failed"); 236 } 237 238 void alarmfunc(int sig) 239 { 240 /* for some reason tst_brkm doesn't seem to work in a signal handler */ 241 tst_brkm(TFAIL, cleanup, "one or more children did't die in 60 second " 242 "time limit"); 243 } 244