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