1 /* 2 * Copyright (c) International Business Machines Corp., 2001 3 * Copyright (c) 2012 Cyril Hrubis <chrubis@suse.cz> 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 * Verify that, pause() returns -1 and sets errno to EINTR after receipt of a 22 * signal which is caught by the calling process. Also, verify that the calling 23 * process will resume execution from the point of suspension. 24 */ 25 26 #include <unistd.h> 27 #include <errno.h> 28 #include <fcntl.h> 29 #include <sys/wait.h> 30 31 #include "test.h" 32 33 char *TCID = "pause02"; 34 int TST_TOTAL = 1; 35 static pid_t cpid; 36 37 static void do_child(void); 38 static void setup(void); 39 static void cleanup(void); 40 41 int main(int ac, char **av) 42 { 43 int lc; 44 int status; 45 46 tst_parse_opts(ac, av, NULL, NULL); 47 48 #ifdef UCLINUX 49 maybe_run_child(&do_child, ""); 50 #endif 51 52 setup(); 53 54 for (lc = 0; TEST_LOOPING(lc); lc++) { 55 tst_count = 0; 56 57 cpid = FORK_OR_VFORK(); 58 switch (cpid) { 59 case -1: 60 tst_brkm(TBROK, cleanup, "fork() failed"); 61 break; 62 case 0: 63 #ifdef UCLINUX 64 if (self_exec(av[0], "") < 0) 65 tst_brkm(TBROK, cleanup, "self_exec failed"); 66 #else 67 do_child(); 68 #endif 69 break; 70 default: 71 break; 72 } 73 74 /* 75 * Wait for child to enter pause(). 76 */ 77 TST_PROCESS_STATE_WAIT(cleanup, cpid, 'S'); 78 79 /* 80 * Send the SIGINT signal now, so that child 81 * returns from pause and resumes execution. 82 */ 83 kill(cpid, SIGINT); 84 85 wait(&status); 86 87 if (WIFEXITED(status)) { 88 if (WEXITSTATUS(status) == 0) 89 tst_resm(TPASS, "pause was interrupted correctly"); 90 else 91 tst_resm(TFAIL, "pause was interrupted but the " 92 "retval and/or errno was wrong"); 93 continue; 94 } 95 96 if (WIFSIGNALED(status)) { 97 switch (WTERMSIG(status)) { 98 case SIGALRM: 99 tst_resm(TFAIL, "Timeout: SIGINT wasn't recieved by child"); 100 break; 101 default: 102 tst_resm(TFAIL, "Child killed by signal"); 103 } 104 105 continue; 106 } 107 108 tst_resm(TFAIL, "Pause was not interrupted"); 109 } 110 111 cleanup(); 112 tst_exit(); 113 } 114 115 static void sig_handle(int sig) 116 { 117 } 118 119 static void do_child(void) 120 { 121 /* avoid LTP framework to do whatever it likes */ 122 signal(SIGALRM, SIG_DFL); 123 124 if (signal(SIGINT, sig_handle) == SIG_ERR) { 125 fprintf(stderr, "Child: Failed to setup signal handler\n"); 126 exit(1); 127 } 128 129 /* Commit suicide after 10 seconds */ 130 alarm(10); 131 132 TEST(pause()); 133 134 if (TEST_RETURN == -1) { 135 if (TEST_ERRNO == EINTR) 136 exit(0); 137 138 fprintf(stderr, "Child: Pause returned -1 but errno is %d (%s)\n", 139 TEST_ERRNO, strerror(TEST_ERRNO)); 140 exit(1); 141 } 142 143 fprintf(stderr, "Child: Pause returned %ld\n", TEST_RETURN); 144 exit(1); 145 } 146 147 static void setup(void) 148 { 149 tst_sig(FORK, DEF_HANDLER, cleanup); 150 151 TEST_PAUSE; 152 } 153 154 static void cleanup(void) 155 { 156 } 157