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 */
85void init_sig();
86void handler(int sig);		//, int code, struct sigcontext *);
87void reset_valid_sig();
88void sys_error(const char *, int);
89void error(const char *, int);
90
91/* Define an array for verifying received signals */
92int valid_sig[SIGMAX + 1];
93
94/*---------------------------------------------------------------------+
95|                               main ()                                |
96| ==================================================================== |
97|                                                                      |
98| Function:  Main program  (see prolog for more details)               |
99|                                                                      |
100+---------------------------------------------------------------------*/
101int 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+---------------------------------------------------------------------*/
278void 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+---------------------------------------------------------------------*/
327void 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+---------------------------------------------------------------------*/
351void 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+---------------------------------------------------------------------*/
366void 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+---------------------------------------------------------------------*/
381void error(const char *msg, int line)
382{
383	fprintf(stderr, "ERROR [line: %d] %s\n", line, msg);
384	exit(-1);
385}
386