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_01 |
21 | ==================================================================== |
22 | |
23 | Description: Simplistic test to verify the signal system function |
24 | calls: |
25 | |
26 | Algorithm: 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 | sigstack () - Sets signal stack context |
43 | sigsetmask () - Sets the current signal mask |
44 | sigblock () - Sets the current signal mask |
45 | sigpause () - Automically changes the set of blocked |
46 | signals and waits for a signal |
47 | sigvec () - Specify the action to take upon delivery |
48 | of a signal. |
49 | kill () - Sends a signal to a process |
50 | |
51 | Usage: signal_test_01 |
52 | |
53 | To compile: cc -o signal_test_01 signal_test_01.c |
54 | |
55 | Last update: Ver. 1.3, 4 June 2001 |
56 | |
57 | Change Activity |
58 | |
59 | Version Date Name Reason |
60 | 0.1 050689 CTU Initial version |
61 | 0.2 112293 DJK Rewrite for AIX version 4.1 |
62 | 1.2 020794 DJK Move to "prod" directory |
63 | 1.3 060401 VHM Port to work in linux |
64 | |
65 +---------------------------------------------------------------------*/
66
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <errno.h>
71 #ifdef _LINUX_
72 #define __USE_XOPEN
73 #endif
74 #include <signal.h>
75 #include <unistd.h>
76
77 /* Macro for specifying signal masks */
78 #define STACKSIZE SIGSTKSZ
79
80 /* Define an alternative stack for processing signals */
81 char stackarray[STACKSIZE];
82
83 #include "signals.h"
84
85 #ifdef _LINUX_
86 stack_t stack = {
87 ss_sp: stackarray + STACKSIZE, // stack pointer
88 ss_flags:0, //SS_ONSTACK, // flags
89 ss_size:STACKSIZE // size
90 };
91
92 stack_t *oldstack;
93
94 // SIGMAX is defined in the AIX headers to be 63 - 64 seems to work in linux??
95 // however, signals 32, 33, and 34 are not valid
96 #define SIGMAX 64
97
98 #else // ! _LINUX_
99
100 struct sigstack stack = {
101 stackarray + STACKSIZE, /* signal stack pointer */
102 (_ONSTACK & ~_OLDSTYLE) /* current status */
103 };
104 #endif
105
106 /* Function prototypes */
107 void handler(int); /* signal catching function */
108 void init_sig_vec(); /* setup signal handler for signals */
109 void reset_valid_sig(); /* reset valid_sig array */
110 void sys_error(const char *, int); /* system error message function */
111 void error(const char *, int); /* error message function */
112
113 /* Define an array for verifying received signals */
114 int valid_sig[SIGMAX + 1];
115
116 /*---------------------------------------------------------------------+
117 | main () |
118 | ==================================================================== |
119 | |
120 | Function: Main program (see prolog for more details) |
121 | |
122 +---------------------------------------------------------------------*/
main(int argc,char ** argv)123 int main(int argc, char **argv)
124 {
125 sigset_t mask, /* Initial process signal mask */
126 newmask, /* Second process signal mask */
127 oldmask; /* Signal mask returned by sigblock */
128 pid_t pid = getpid(); /* Process ID (of this process) */
129
130 /* Print out program header */
131 printf("%s: IPC Signals TestSuite program\n\n", *argv);
132
133 /*
134 * Establish signal handler for each signal & reset "valid signals"
135 * array, and setup alternative stack for processing signals
136 */
137 init_sig_vec();
138 reset_valid_sig();
139 #ifdef _LINUX_
140 // sigstack function is obsolete, use sigaltstack instead
141 if (sigaltstack(&stack, NULL) < 0)
142 sys_error("sigaltstack failed", __LINE__);
143 #else
144 if (sigstack(&stack, NULL) < 0)
145 sys_error("sigstack failed", __LINE__);
146 #endif
147 /*
148 * Send SIGILL, SIGALRM & SIGIOT signals to this process:
149 *
150 * First indicate which signals the signal handler should expect
151 * by setting the corresponding valid_sig[] array fields.
152 *
153 * Then send the signals to this process.
154 *
155 * And finally verify that the signals were caught by the signal
156 * handler by checking to see if the corresponding valid_sig[] array
157 * fields were reset.
158 */
159 printf("\tSend SIGILL, SIGALRM, SIGIOT signals to process\n");
160 valid_sig[SIGILL] = 1;
161 valid_sig[SIGALRM] = 1;
162 valid_sig[SIGIOT] = 1;
163
164 kill(pid, SIGILL);
165 kill(pid, SIGALRM);
166 kill(pid, SIGIOT);
167
168 if (valid_sig[SIGILL])
169 error("failed to receive SIGILL signal!", __LINE__);
170 if (valid_sig[SIGALRM])
171 error("failed to receive SIGALRM signal!", __LINE__);
172 if (valid_sig[SIGIOT])
173 error("failed to receive SIGIOT signal!", __LINE__);
174
175 /*
176 * Block SIGILL, SIGALRM & SIGIOT signals:
177 *
178 * First create the process signal mask by ORing together the
179 * signal values.
180 *
181 * Then change the process signal mask with sigsetmask ().
182 *
183 * Verify that the desired signals are blocked from interrupting the
184 * process, by sending both blocked and unblocked signals to the
185 * process. Only the unblocked signals should interrupt the process.
186 */
187 printf("\n\tBlock SIGILL, SIGALRM, SIGIOT signals, "
188 "and resend signals + others\n");
189 sigemptyset(&mask);
190 sigaddset(&mask, SIGILL);
191 sigaddset(&mask, SIGALRM);
192 sigaddset(&mask, SIGIOT);
193 #ifdef _LINUX_
194 sigprocmask(SIG_SETMASK, &mask, NULL);
195 #else
196 if (sigsetmask(mask) < 0)
197 sys_error("setsigmask failed", __LINE__);
198 #endif
199 valid_sig[SIGFPE] = 1;
200 valid_sig[SIGTERM] = 1;
201 valid_sig[SIGINT] = 1;
202
203 kill(pid, SIGILL);
204 kill(pid, SIGALRM);
205 kill(pid, SIGIOT);
206 kill(pid, SIGFPE);
207 kill(pid, SIGTERM);
208 kill(pid, SIGINT);
209
210 if (valid_sig[SIGFPE])
211 error("failed to receive SIGFPE signal!", __LINE__);
212 if (valid_sig[SIGTERM])
213 error("failed to receive SIGTERM signal!", __LINE__);
214 if (valid_sig[SIGINT])
215 error("failed to receive SIGINT signal!", __LINE__);
216
217 /*
218 * Block additional SIGFPE, SIGTERM & SIGINT signals:
219 *
220 * Create a signal mask containing the additional signals to block.
221 *
222 * Change the process signal mask to block the additional signals
223 * with the sigprocmask () function.
224 *
225 * Verify that all of the desired signals are now blocked from
226 * interrupting the process. None of the specified signals should
227 * interrupt the process until the process signal mask is changed.
228 */
229 printf("\n\tBlock rest of signals\n");
230 sigemptyset(&newmask);
231 sigaddset(&newmask, SIGFPE);
232 sigaddset(&newmask, SIGTERM);
233 sigaddset(&newmask, SIGINT);
234 sigemptyset(&oldmask);
235 if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
236 perror("sigprocmask failed");
237 exit(-1);
238 }
239 if (memcmp(&mask, &oldmask, sizeof(mask)) != 0)
240 error("value returned by sigblock () does not match the "
241 "old signal mask", __LINE__);
242
243 kill(pid, SIGILL);
244 kill(pid, SIGALRM);
245 kill(pid, SIGIOT);
246 kill(pid, SIGFPE);
247 kill(pid, SIGTERM);
248 kill(pid, SIGINT);
249
250 /* Wait two seconds just to make sure that none of the specified
251 * signals interrupt the process (They should all be blocked).
252 */
253 sleep(2);
254
255 /* Change the process signal mask:
256 *
257 * Now allow the SIGINT signal to interrupt the process.
258 * Thus by using sigpause (), force the process to suspend
259 * execution until delivery of an unblocked signal (here SIGINT).
260 *
261 * Additionally, verify that the SIGINT signal was received.
262 */
263 valid_sig[SIGINT] = 1;
264
265 printf
266 ("\n\tChange signal mask & wait until signal interrupts process\n");
267 if (sigpause(SIGINT) != -1 || errno != 4)
268 sys_error("sigpause failed", __LINE__);
269
270 if (valid_sig[SIGINT])
271 error("failed to receive SIGINT signal!", __LINE__);
272
273 /* Program completed successfully -- exit */
274 printf("\nsuccessful!\n");
275
276 return (0);
277 }
278
279 /*---------------------------------------------------------------------+
280 | init_sig_vec () |
281 | ==================================================================== |
282 | |
283 | Function: Initialize the signal vector for ALL possible signals |
284 | (as defined in /usr/include/sys/signal.h) except for |
285 | the following signals which cannot be caught or ignored: |
286 | |
287 | o SIGKILL (9) |
288 | o SIGSTOP (17) |
289 | o SIGCONT (19) |
290 | |
291 | Returns: Nothing |
292 | |
293 +---------------------------------------------------------------------*/
init_sig_vec()294 void init_sig_vec()
295 {
296 char errmsg[256];
297 int i;
298
299 #ifdef _LINUX_
300 static struct sigaction invec;
301
302 for (i = 1; i <= SIGMAX; i++) {
303 if ((i == SIGKILL) || (i == SIGSTOP)
304 || ((i >= 32) && (i <= 34)))
305 continue;
306 invec.sa_handler = handler;
307 //sigaction.sa_mask = 0;
308 invec.sa_flags = 0;
309
310 if (sigaction(i, &invec, NULL)) {
311 sprintf(errmsg,
312 "init_sig_vec: sigaction failed on signal (%d)",
313 i);
314 perror(errmsg);
315 sys_error(errmsg, __LINE__);
316 }
317 }
318 #else
319 static struct sigvec invec;
320
321 for (i = 1; i <= SIGMAX; i++) {
322
323 /* Cannot catch or ignore the following signals */
324 #ifdef _IA64 /* SIGWAITING NOT supported, RESERVED */
325 if ((i == SIGKILL) || (i == SIGSTOP) ||
326 (i == SIGCONT) || (i == SIGWAITING))
327 continue;
328 #else
329 if ((i == SIGKILL) || (i == SIGSTOP) || (i == SIGCONT))
330 continue;
331 #endif
332
333 invec.sv_handler = handler;
334 //invec.sv_mask = SA_NOMASK;
335 #if defined _IA64
336 invec.sv_flags = 1;
337 #else
338 invec.sv_onstack = 1;
339 #endif
340 if (sigvec(i, &invec, NULL)) {
341 sprintf(errmsg,
342 "init_sig_vec: sigvec failed on signal (%d)",
343 i);
344 perror(errmsg);
345 sys_error(errmsg, __LINE__);
346 }
347 }
348 #endif //ifdef _LINUX_
349 }
350
351 /*---------------------------------------------------------------------+
352 | handler () |
353 | ==================================================================== |
354 | |
355 | Function: Signal catching function. As specified in init_sig_vec() |
356 | this function is automatically called each time a signal |
357 | is received by the process. |
358 | |
359 | Once receiving the signal, verify that the corresponding |
360 | signal was expected. |
361 | |
362 | Returns: Aborts program if an unexpected signal was received. |
363 | |
364 +---------------------------------------------------------------------*/
handler(int sig)365 void handler(int sig)
366 {
367 char errmsg[256];
368
369 /* Check to insure that expected signal was received */
370 if (valid_sig[sig]) {
371 valid_sig[sig] = 0;
372 printf("\treceived signal: (%s)\n", signames[sig]);
373 } else {
374 sprintf(errmsg, "unexpected signal (%d,%s)", sig,
375 (sig < 32) ? signames[sig] : "unknown signal");
376 error(errmsg, __LINE__);
377 }
378 }
379
380 /*---------------------------------------------------------------------+
381 | reset_valid_sig () |
382 | ==================================================================== |
383 | |
384 | Function: Reset the valid "signal" array |
385 | |
386 | Returns: Nothing |
387 | |
388 +---------------------------------------------------------------------*/
reset_valid_sig()389 void reset_valid_sig()
390 {
391 int i;
392
393 for (i = 0; i < (SIGMAX + 1); i++)
394 valid_sig[i] = 0;
395 }
396
397 /*---------------------------------------------------------------------+
398 | sys_error () |
399 | ==================================================================== |
400 | |
401 | Function: Creates system error message and calls error () |
402 | |
403 +---------------------------------------------------------------------*/
sys_error(const char * msg,int line)404 void sys_error(const char *msg, int line)
405 {
406 char syserr_msg[256];
407
408 sprintf(syserr_msg, "%s: %s\n", msg, strerror(errno));
409 error(syserr_msg, line);
410 }
411
412 /*---------------------------------------------------------------------+
413 | error () |
414 | ==================================================================== |
415 | |
416 | Function: Prints out message and exits... |
417 | |
418 +---------------------------------------------------------------------*/
error(const char * msg,int line)419 void error(const char *msg, int line)
420 {
421 char derr[256];
422 sprintf(derr, "ERROR [line: %d] %s\n", line, msg);
423 perror(derr);
424 exit(-1);
425 }
426