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 +---------------------------------------------------------------------*/
main(int argc,char ** argv)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 +---------------------------------------------------------------------*/
init_sig()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 +---------------------------------------------------------------------*/
handler(int sig)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 +---------------------------------------------------------------------*/
reset_valid_sig()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 +---------------------------------------------------------------------*/
sys_error(const char * msg,int line)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 +---------------------------------------------------------------------*/
error(const char * msg,int line)381 void error(const char *msg, int line)
382 {
383 fprintf(stderr, "ERROR [line: %d] %s\n", line, msg);
384 exit(-1);
385 }
386