1 /* 2 * Copyright (C) Bull S.A. 1996 3 * Copyright (c) International Business Machines Corp., 2001 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 | signal_test_02 | 21 | ==================================================================== | 22 | | 23 | Description: Simplistic test to verify the signal system function | 24 | calls: | 25 | | 26 | o Setup a signal-catching function for every possible | 27 | signal. | 28 | o Send signals to the process and verify that they | 29 | were received by the signal-catching function. | 30 | o Block a few signals by changing the process signal | 31 | mask. Send signals to the process and verify that | 32 | they indeed were blocked. | 33 | o Add additional signals to the process signal mask. | 34 | Verify that they were blocked too. | 35 | o Change the process signal mask to unblock one | 36 | signal and suspend execution of the process until | 37 | the signal is received. Verify that the unblocked | 38 | signal is received. | 39 | | 40 | System calls: The following system calls are tested: | 41 | | 42 | sigprocmask () - Sets the current signal mask | 43 | sigemptyset () - Creates and manipulates signal masks | 44 | sigfillset () - Creates and manipulates signal masks | 45 | sigaddset () - Creates and manipulates signal masks | 46 | sigdelset () - Creates and manipulates signal masks | 47 | sigsuspend () - Atomically changes the set of blocked | 48 | signals and waits for a signal | 49 | sigaction () - Specifies the action to take upon | 50 | delivery of a signal | 51 | kill () - Sends a signal to a process | 52 | | 53 | Usage: signal_test_03 | 54 | | 55 | To compile: cc -o signal_test_03 signal_test_03 | 56 | | 57 | Last update: Ver. 1.2, 2/7/94 23:17:48 | 58 | | 59 | Change Activity | 60 | | 61 | Version Date Name Reason | 62 | 0.1 050689 CTU Initial version | 63 | 0.2 112293 DJK Rewrite for AIX version 4.1 | 64 | 1.2 020794 DJK Move to "prod" directory | 65 | 1.3 060501 VHM Port to work in linux | 66 | | 67 +---------------------------------------------------------------------*/ 68 69 #define SIGMAX 64 /* What should this number really be? _NSIG from bits/signum.h maybe? */ 70 71 #include <stdio.h> 72 #include <stdlib.h> 73 #include <errno.h> 74 #include <signal.h> 75 #include <string.h> 76 #include <unistd.h> 77 #include <sys/types.h> 78 79 /* Macro for specifying signal masks */ 80 #define MASK(sig) (1 << ((sig) - 1)) 81 82 #include "signals.h" 83 84 /* Function prototypes */ 85 void init_sig(); 86 void handler(int sig); //, int code, struct sigcontext *); 87 void reset_valid_sig(); 88 void sys_error(const char *, int); 89 void error(const char *, int); 90 91 /* Define an array for verifying received signals */ 92 int valid_sig[SIGMAX + 1]; 93 94 /*---------------------------------------------------------------------+ 95 | main () | 96 | ==================================================================== | 97 | | 98 | Function: Main program (see prolog for more details) | 99 | | 100 +---------------------------------------------------------------------*/ 101 int main(int argc, char **argv) 102 { 103 sigset_t setsig, /* Initial signal mask */ 104 newsetsig; /* Second signal mask */ 105 pid_t pid = getpid(); /* Process ID (of this process) */ 106 107 /* Print out program header */ 108 printf("%s: IPC TestSuite program\n\n", *argv); 109 110 /* 111 * Establish signal handler for each signal & reset "valid signals" 112 * array 113 */ 114 init_sig(); 115 reset_valid_sig(); 116 117 sigemptyset(&setsig); 118 if (sigprocmask(SIG_SETMASK, &setsig, NULL) < 0) 119 sys_error("sigprocmask failed", __LINE__); 120 121 /* 122 * Send SIGILL, SIGALRM & SIGIOT signals to this process: 123 * 124 * First indicate which signals the signal handler should expect 125 * by setting the corresponding valid_sig[] array fields. 126 * 127 * Then send the signals to this process. 128 * 129 * And finally verify that the signals were caught by the signal 130 * handler by checking to see if the corresponding valid_sig[] array 131 * fields were reset. 132 */ 133 printf("\tSend SIGILL, SIGALRM, SIGIOT signals to process\n"); 134 valid_sig[SIGILL] = 1; 135 valid_sig[SIGALRM] = 1; 136 valid_sig[SIGIOT] = 1; 137 138 kill(pid, SIGILL); 139 kill(pid, SIGALRM); 140 kill(pid, SIGIOT); 141 142 if (valid_sig[SIGILL]) 143 error("failed to receive SIGILL signal!", __LINE__); 144 if (valid_sig[SIGALRM]) 145 error("failed to receive SIGALRM signal!", __LINE__); 146 if (valid_sig[SIGIOT]) 147 error("failed to receive SIGIOT signal!", __LINE__); 148 149 /* 150 * Block SIGILL, SIGALRM & SIGIOT signals: 151 * 152 * First initialize the signal set so that all signals are excluded, 153 * then individually add the signals to block to the signal set. 154 * 155 * Then change the process signal mask with sigprocmask (SIG_SETMASK). 156 * 157 * Verify that the desired signals are blocked from interrupting the 158 * process, by sending both blocked and unblocked signals to the 159 * process. Only the unblocked signals should interrupt the process. 160 */ 161 printf("\n\tBlock SIGILL, SIGALRM, SIGIOT signals, " 162 "and resend signals + others\n"); 163 sigemptyset(&setsig); 164 165 if (sigaddset(&setsig, SIGIOT) < 0) 166 sys_error("sigaddset (SIGIOT) failed", __LINE__); 167 if (sigaddset(&setsig, SIGILL) < 0) 168 sys_error("sigaddset (SIGILL) failed", __LINE__); 169 if (sigaddset(&setsig, SIGALRM) < 0) 170 sys_error("sigaddset (SIGALRM) failed", __LINE__); 171 172 if (sigprocmask(SIG_SETMASK, &setsig, NULL) < 0) 173 sys_error("sigaddset (SIGALRM) failed", __LINE__); 174 175 valid_sig[SIGFPE] = 1; 176 valid_sig[SIGTERM] = 1; 177 valid_sig[SIGINT] = 1; 178 179 kill(pid, SIGILL); 180 kill(pid, SIGALRM); 181 kill(pid, SIGIOT); 182 kill(pid, SIGFPE); 183 kill(pid, SIGTERM); 184 kill(pid, SIGINT); 185 186 if (valid_sig[SIGFPE]) 187 sys_error("failed to receive SIGFPE signal!", __LINE__); 188 if (valid_sig[SIGTERM]) 189 sys_error("failed to receive SIGTERM signal!", __LINE__); 190 if (valid_sig[SIGINT]) 191 sys_error("failed to receive SIGINT signal!", __LINE__); 192 193 /* 194 * Block additional SIGFPE, SIGTERM & SIGINT signals: 195 * 196 * Create an other signal set to contain the additional signals to block 197 * and add the signals to block to the signal set. 198 * 199 * Change the process signal mask to block the additional signals 200 * with the sigprocmask (SIG_BLOCK) function. 201 * 202 * Verify that all of the desired signals are now blocked from 203 * interrupting the process. None of the specified signals should 204 * interrupt the process until the process signal mask is changed. 205 */ 206 printf("\n\tBlock rest of signals\n"); 207 sigemptyset(&newsetsig); 208 209 sigaddset(&newsetsig, SIGFPE); 210 sigaddset(&newsetsig, SIGTERM); 211 sigaddset(&newsetsig, SIGINT); 212 213 if (sigprocmask(SIG_BLOCK, &newsetsig, &setsig) < 0) 214 sys_error("sigprocmask failed", __LINE__); 215 216 kill(pid, SIGILL); 217 kill(pid, SIGALRM); 218 kill(pid, SIGIOT); 219 kill(pid, SIGFPE); 220 kill(pid, SIGTERM); 221 kill(pid, SIGINT); 222 223 /* 224 * Wait two seconds just to make sure that none of the specified 225 * signals interrupt the process (They should all be blocked). 226 */ 227 sleep(2); 228 229 /* 230 * Change the process signal mask: 231 * 232 * Now specifiy a new process signal set to allow the SIGINT signal 233 * to interrupt the process. Create the signal set by initializing 234 * the signal set with sigfillset () so that all signals are included 235 * in the signal set, then remove the SIGINT signal from the set with 236 * sigdelset (). 237 * 238 * Force the process to suspend execution until delivery of an 239 * unblocked signal (SIGINT in this case) with sigsuspend (). 240 * 241 * Additionally, verify that the SIGINT signal was received. 242 */ 243 valid_sig[SIGINT] = 1; 244 245 printf 246 ("\n\tChange signal mask & wait until signal interrupts process\n"); 247 if (sigfillset(&setsig) < 0) 248 sys_error("sigfillset failed", __LINE__); 249 if (sigdelset(&setsig, SIGINT) < 0) 250 sys_error("sigdelset failed", __LINE__); 251 if (sigsuspend(&setsig) != -1 || errno != 4) 252 sys_error("sigsuspend failed", __LINE__); 253 254 if (valid_sig[SIGINT]) 255 error("failed to receive SIGIOT signal!", __LINE__); 256 257 /* Program completed successfully -- exit */ 258 printf("\nsuccessful!\n"); 259 260 return (0); 261 } 262 263 /*---------------------------------------------------------------------+ 264 | init_sig () | 265 | ==================================================================== | 266 | | 267 | Function: Initialize the signal vector for ALL possible signals | 268 | (as defined in /usr/include/sys/signal.h) except for | 269 | the following signals which cannot be caught or ignored: | 270 | | 271 | o SIGKILL (9) | 272 | o SIGSTOP (17) | 273 | o SIGCONT (19) | 274 | | 275 | Returns: n/a | 276 | | 277 +---------------------------------------------------------------------*/ 278 void init_sig() 279 { 280 struct sigaction invec; 281 char msg[256]; /* Buffer for error message */ 282 int i; 283 284 for (i = 1; i <= SIGMAX; i++) { 285 286 /* Cannot catch or ignore the following signals */ 287 #ifdef _IA64 /* SIGWAITING not supported, RESERVED */ 288 if ((i == SIGKILL) || (i == SIGSTOP) || 289 (i == SIGCONT) || (i == SIGWAITING)) 290 continue; 291 #else 292 #ifdef _LINUX_ 293 if ((i == SIGKILL) || (i == SIGSTOP) 294 || ((i >= 32) && (i <= 34))) 295 continue; 296 #else 297 if (i == SIGKILL || i == SIGSTOP || i == SIGCONT) 298 continue; 299 #endif 300 #endif 301 302 invec.sa_handler = (void (*)(int))handler; 303 sigemptyset(&invec.sa_mask); 304 invec.sa_flags = 0; 305 306 if (sigaction(i, &invec, NULL) < 0) { 307 sprintf(msg, "sigaction failed on signal %d", i); 308 error(msg, __LINE__); 309 } 310 } 311 } 312 313 /*---------------------------------------------------------------------+ 314 | handler () | 315 | ==================================================================== | 316 | | 317 | Function: Signal catching function. As specified in init_sig_vec() | 318 | this function is automatically called each time a signal | 319 | is received by the process. | 320 | | 321 | Once receiving the signal, verify that the corresponding | 322 | signal was expected. | 323 | | 324 | Returns: Aborts program if an unexpected signal was received. | 325 | | 326 +---------------------------------------------------------------------*/ 327 void handler(int sig) //, int code, struct sigcontext *scp) 328 { 329 char msg[256]; 330 331 /* Check to insure that expected signal was received */ 332 if (valid_sig[sig]) { 333 valid_sig[sig] = 0; 334 printf("\treceived signal: (%s)\n", signames[sig]); 335 } else { 336 sprintf(msg, "unexpected signal (%d,%s)", sig, 337 (sig < 32) ? signames[sig] : "unknown signal"); 338 error(msg, __LINE__); 339 } 340 } 341 342 /*---------------------------------------------------------------------+ 343 | reset_valid_sig () | 344 | ==================================================================== | 345 | | 346 | Function: Reset the valid "signal" array | 347 | | 348 | Returns: n/a | 349 | | 350 +---------------------------------------------------------------------*/ 351 void reset_valid_sig() 352 { 353 int i; 354 355 for (i = 0; i < (SIGMAX + 1); i++) 356 valid_sig[i] = 0; 357 } 358 359 /*---------------------------------------------------------------------+ 360 | sys_error () | 361 | ==================================================================== | 362 | | 363 | Function: Creates system error message and calls error () | 364 | | 365 +---------------------------------------------------------------------*/ 366 void sys_error(const char *msg, int line) 367 { 368 char syserr_msg[256]; 369 370 sprintf(syserr_msg, "%s: %s\n", msg, strerror(errno)); 371 error(syserr_msg, line); 372 } 373 374 /*---------------------------------------------------------------------+ 375 | error () | 376 | ==================================================================== | 377 | | 378 | Function: Prints out message and exits... | 379 | | 380 +---------------------------------------------------------------------*/ 381 void error(const char *msg, int line) 382 { 383 fprintf(stderr, "ERROR [line: %d] %s\n", line, msg); 384 exit(-1); 385 } 386