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_03                             |
21 | ==================================================================== |
22 |                                                                      |
23 | Description:  Block a critical section from receiving signals.       |
24 |                                                                      |
25 | Algorithm:    o  Setup a signal-catching function                    |
26 |               o  Beginning of Critical section -- Set the process    |
27 |                  signal mask to block the SIGILL signal              |
28 |               o  Send SIGILL signal to the process to insure that    |
29 |                  the signal is blocked during the critical section   |
30 |               o  Preform the critical section code (merely sleep     |
31 |                  for testing purposes)                               |
32 |               o  Verify that the signal was blocked                  |
33 |               o  End of Critical section -- unblock the signal and   |
34 |                  suspend he process signal mask to unblock one       |
35 |                  signal and suspend execution of the process until   |
36 |                  the signal is received.  Verify that the unblocked  |
37 |                  signal is received.                                 |
38 |                                                                      |
39 | System calls: The following system calls are tested:                 |
40 |                                                                      |
41 |               sigsetmask () - Sets the current signal mask           |
42 |               sigblock () - Sets the current signal mask             |
43 |               sigvec () - Specify the action to take upon delivery   |
44 |                           of a signal.                               |
45 |               raise () - Sends a signal to the executing program     |
46 |                                                                      |
47 | Usage:        signal_test_03                                         |
48 |                                                                      |
49 | To compile:   cc -o signal_test_03 signal_test_03                    |
50 |                                                                      |
51 | Last update:   Ver. 1.2, 2/7/94 23:23:34                           |
52 |                                                                      |
53 | Change Activity                                                      |
54 |                                                                      |
55 |   Version  Date    Name  Reason                                      |
56 |    0.1     050689  CTU   Initial version                             |
57 |    1.2     112293  DJK   Rewrite for AIX version 4.1                 |
58 |                                                                      |
59 +---------------------------------------------------------------------*/
60 
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <signal.h>
64 #include <string.h>
65 #include <unistd.h>
66 #include <errno.h>
67 
68 #define MASK(sig)  (1 << ((sig) - 1))
69 #define MAXTIME	2		/* MAX timeout (minutes) */
70 
71 #ifdef _LINUX_
72 // bits/signum.h defines _NSIG as 64
73 #define SIGMAX 64
74 #endif
75 
76 #include "signals.h"
77 
78 /* Function prototypes */
79 void handler(int);
80 void init_sig_vec();
81 void sys_error(const char *, int);
82 void error(const char *, int);
83 
84 /* Global variables */
85 int signals_received = 0;
86 
87 /*---------------------------------------------------------------------+
88 |                               main ()                                |
89 | ==================================================================== |
90 |                                                                      |
91 | Function:  Main program  (see prolog for more details)               |
92 |                                                                      |
93 +---------------------------------------------------------------------*/
main(int argc,char ** argv)94 int main(int argc, char **argv)
95 {
96 	int timeout = MAXTIME * 60;	/* Number sec to wait for signal */
97 
98 	/* Print out program header */
99 	printf("%s: IPC Signals TestSuite program\n\n", *argv);
100 
101 	/* Set up our signal handlers */
102 	init_sig_vec();
103 
104 	/*
105 	 * Critical section - block SIGILL signal
106 	 *
107 	 * Block the SIGILL interrupt from interrupting the process
108 	 * with the sigprocmask () system function call.
109 	 *
110 	 * Send the SIGILL interrupt to the process in an attempt to
111 	 * disrupt the critial section -- the signal should be blocked.
112 	 * Wait one second to insure that the signal has plenty of time
113 	 * to reach the process.
114 	 */
115 #ifdef _LINUX_
116 	sigset_t mask;
117 	sigemptyset(&mask);
118 	sigaddset(&mask, SIGILL);
119 	sigprocmask(SIG_BLOCK, &mask, NULL);
120 #else
121 	if (sigblock(MASK(SIGILL)) < 0)
122 		sys_error("sigblock failed", __LINE__);
123 #endif
124 
125 	printf("\t(BEGIN) Critial section\n");
126 
127 	/* Critial section */
128 	sleep(1);
129 
130 	/*
131 	 * End of critical section - ensure SIGILL signal was not received
132 	 *
133 	 * Check to insure that the signal handler has not caught any signals,
134 	 * and then unblock all of the signals with the sigsetmask system
135 	 * function call.
136 	 */
137 	if (signals_received > 0)
138 		error
139 		    ("received an unexpected signal during the critical section",
140 		     __LINE__);
141 
142 	printf("\n\t(END) Critial section\n");
143 
144 #ifdef _LINUX_
145 	sigemptyset(&mask);
146 	sigprocmask(SIG_SETMASK, &mask, NULL);
147 #else
148 	if (sigsetmask(0) < 0)
149 		sys_error("sigsetmask failed", __LINE__);
150 #endif
151 	raise(SIGILL);
152 
153 	/*
154 	 * Upon unblocking the signals, should receive the SIGILL signal.
155 	 * Verify that it indeed is caught.
156 	 */
157 	while (signals_received == 0 && --timeout) {
158 		printf(".");
159 		fflush(stdout);
160 		sleep(1);
161 	}
162 
163 	if (timeout == 0)
164 		error
165 		    ("failed to receive SIGILL signal after unblocking signals",
166 		     __LINE__);
167 
168 	/* Program completed successfully -- exit */
169 	printf("\nsuccessful!\n");
170 	return (0);
171 }
172 
173 /*---------------------------------------------------------------------+
174 |                           init_sig_vec ()                            |
175 | ==================================================================== |
176 |                                                                      |
177 | Function:  Initialize the signal vector for ALL possible signals     |
178 |            (as defined in /usr/include/sys/signal.h) except for      |
179 |            the following signals which cannot be caught or ignored:  |
180 |                                                                      |
181 |              o  SIGKILL (9)                                          |
182 |              o  SIGSTOP (17)                                         |
183 |              o  SIGCONT (19)                                         |
184 |                                                                      |
185 | Returns:   Nothing                                                   |
186 |                                                                      |
187 +---------------------------------------------------------------------*/
init_sig_vec()188 void init_sig_vec()
189 {
190 	struct sigaction invec;
191 	char msg[256];		/* Buffer for error message */
192 	int i;
193 
194 	for (i = 1; i <= SIGMAX; i++) {
195 
196 		/* Cannot catch or ignore the following signals */
197 #ifdef _IA64			/* SIGWAITING not supported, RESERVED */
198 		if ((i == SIGKILL) || (i == SIGSTOP) ||
199 		    (i == SIGCONT) || (i == SIGWAITING))
200 			continue;
201 #else
202 #ifdef _LINUX_
203 		if ((i == SIGKILL) || (i == SIGSTOP)
204 		    || ((i >= 32) && (i <= 34)))
205 			continue;
206 #else
207 		if (i == SIGKILL || i == SIGSTOP || i == SIGCONT)
208 			continue;
209 #endif
210 #endif
211 
212 		invec.sa_handler = (void (*)(int))handler;
213 		sigemptyset(&invec.sa_mask);
214 		invec.sa_flags = 0;
215 
216 		if (sigaction(i, &invec, NULL) < 0) {
217 			sprintf(msg, "sigaction failed on signal %d", i);
218 			error(msg, __LINE__);
219 		}
220 	}
221 }
222 
223 /*---------------------------------------------------------------------+
224 |                             handler ()                               |
225 | ==================================================================== |
226 |                                                                      |
227 | Function:  Signal catching function.  This function is called each   |
228 |            time a non-blocked signal is received by the process.     |
229 |                                                                      |
230 |            Increment the global variable (signals_received) for      |
231 |            each received signal.                                     |
232 |                                                                      |
233 | Returns:   Nothing                                                   |
234 |                                                                      |
235 +---------------------------------------------------------------------*/
handler(int signal)236 void handler(int signal)
237 {
238 	if (signal == SIGILL)
239 		signals_received++;
240 	printf("\treceived signal: (%s)\n", signames[signal]);
241 }
242 
243 /*---------------------------------------------------------------------+
244 |                             sys_error ()                             |
245 | ==================================================================== |
246 |                                                                      |
247 | Function:  Creates system error message and calls error ()           |
248 |                                                                      |
249 +---------------------------------------------------------------------*/
sys_error(const char * msg,int line)250 void sys_error(const char *msg, int line)
251 {
252 	char syserr_msg[256];
253 
254 	sprintf(syserr_msg, "%s: %s\n", msg, strerror(errno));
255 	error(syserr_msg, line);
256 }
257 
258 /*---------------------------------------------------------------------+
259 |                               error ()                               |
260 | ==================================================================== |
261 |                                                                      |
262 | Function:  Prints out message and exits...                           |
263 |                                                                      |
264 +---------------------------------------------------------------------*/
error(const char * msg,int line)265 void error(const char *msg, int line)
266 {
267 	fprintf(stderr, "ERROR [line: %d] %s\n", line, msg);
268 	exit(-1);
269 }
270