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_06                            |
21 | ==================================================================== |
22 |                                                                      |
23 | Description:  Verifies that when multiple identical signals are sent |
24 |               to a process, at least one is queued.                  |
25 |                                                                      |
26 | Algorithm:    o  Block all signals from interrupting the process     |
27 |               o  Send MAXSIG signals to the current process          |
28 |               o  Sleep for a short time                              |
29 |               o  Verify that signals are pending                     |
30 |               o  Change the signal mask and suspend execution until  |
31 |                  a signal interrupts the process                     |
32 |               o  Verify that at least one signal was received        |
33 |                                                                      |
34 | System calls: The following system calls are tested:                 |
35 |                                                                      |
36 |               sigprocmask () - Sets the current signal mask          |
37 |               sigismember () - Creates and manipulates signal masks  |
38 |               sigfillset () - Creates and manipulates signal masks   |
39 |               sigpending () - Returns a set of signals that are      |
40 |                               blocked from delivery                  |
41 |               sigsuspend () - Automatically changes the set of       |
42 |                               blocked signals and waits for a signal |
43 |               raise () - Sends a signal to the executing program     |
44 |                                                                      |
45 | Usage:        signal_test_06                                         |
46 |                                                                      |
47 | To compile:   cc -o signal_test_06 signal_test_06                    |
48 |                                                                      |
49 | Last update:   Ver. 1.2, 2/7/94 23:24:14                           |
50 |                                                                      |
51 | Change Activity                                                      |
52 |                                                                      |
53 |   Version  Date    Name  Reason                                      |
54 |    0.1     122193  DJK   Wrote initial test for AIX version 4.1      |
55 |    1.2     020794  DJK   Move to "prod" directory                    |
56 |                                                                      |
57 +---------------------------------------------------------------------*/
58 
59 #define MAXSIG 1024*1024	/* Number of signals sent to process */
60 
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <unistd.h>
65 #include <sys/signal.h>
66 #include <errno.h>
67 
68 #ifdef _LINUX_
69 // bits/signum.h defines _NSIG as 64
70 #define SIGMAX 64
71 #endif
72 
73 /* Function prototypes */
74 void handler(int, int, struct sigcontext *);
75 void init_sig();
76 void sys_error(const char *, int);
77 void error(const char *, int);
78 
79 /* Global variables */
80 int signals_received = 0;
81 
82 /*---------------------------------------------------------------------+
83 |                               main ()                                |
84 | ==================================================================== |
85 |                                                                      |
86 | Function:  Main program  (see prolog for more details)               |
87 |                                                                      |
88 +---------------------------------------------------------------------*/
main(int argc,char ** argv)89 int main(int argc, char **argv)
90 {
91 	sigset_t newmask,	/* New signal mask */
92 	 oldmask,		/* Initial signal mask */
93 	 pendmask;		/* Pending signal mask */
94 	int i;			/* Loop index */
95 
96 	/* Print out program header */
97 	printf("%s: IPC TestSuite program\n\n", *argv);
98 
99 	/* Set up our signal handler */
100 	init_sig();
101 
102 	/*
103 	 * Block ALL signals from interrupting the process
104 	 */
105 	printf("\tBlock all signals from interrupting the process\n");
106 	if (sigfillset(&newmask) < 0)
107 		error("sigfillset failed", __LINE__);
108 	if (sigprocmask(SIG_SETMASK, &newmask, &oldmask) < 0)
109 		error("sigprocmask failed", __LINE__);
110 
111 	/*
112 	 * Send MAXSIG signals to the current process -- since ALL of the
113 	 * signals are blocked, none of the signals should interrupt the
114 	 * process
115 	 */
116 	printf("\n\tSend MAX (%d) SIGUSR1 signals to the process...\n", MAXSIG);
117 	for (i = 0; i < MAXSIG; i++)
118 		raise(SIGUSR1);
119 
120 	/*
121 	 *  Sleep for a short time and the check to ensure that a SIGUSR1
122 	 *  signal is pending
123 	 */
124 	sleep(2);
125 
126 	printf("\n\tEnsure at least one SIGUSR1 signal is pending\n");
127 	if (sigpending(&pendmask) < 0)
128 		error("sigpending failed", __LINE__);
129 
130 	if (sigismember(&pendmask, SIGUSR1) == 0)
131 		error("sent multiple SIGUSR1 signals to process, "
132 		      "yet none are pending!", __LINE__);
133 
134 	/*
135 	 * Change the signal mask to allow signals to interrupt the process
136 	 * and then suspend execution until a signal reaches the process
137 	 *
138 	 * Then verify that at least one signal was received
139 	 */
140 	printf("\n\tChange signal mask & wait for SIGUSR1 signal\n");
141 	if (sigsuspend(&oldmask) != -1 || errno != 4)
142 		error("sigsuspend failed", __LINE__);
143 
144 	if (signals_received != 1) {
145 		printf("Signals are queued!  Sent %d signals, "
146 		       "while %d were queued\n", MAXSIG, signals_received);
147 	}
148 
149 	/* Program completed successfully -- exit */
150 	printf("\nsuccessful!\n");
151 	return (0);
152 }
153 
154 /*---------------------------------------------------------------------+
155 |                               handler ()                             |
156 | ==================================================================== |
157 |                                                                      |
158 | Function:  Catches signals and aborts the program if a signal other  |
159 |            than SIGUSR1 was received                                 |
160 |                                                                      |
161 | Updates:   signals_received - global variable indicating the number  |
162 |                               of SIGUSR1 signals received            |
163 |                                                                      |
164 | Returns:   Aborts if an unexpected signal is caught                  |
165 |                                                                      |
166 +---------------------------------------------------------------------*/
handler(int signal,int code,struct sigcontext * scp)167 void handler(int signal, int code, struct sigcontext *scp)
168 {
169 	char msg[256];		/* Buffer for error message */
170 
171 	if (signal != SIGUSR1) {
172 		sprintf(msg, "unexpected signal (%d)", signal);
173 		error(msg, __LINE__);
174 	}
175 
176 	printf("\tcaught SIGUSR1 (%d) signal\n", signal);
177 	signals_received++;
178 }
179 
180 /*---------------------------------------------------------------------+
181 |                             init_sig ()                              |
182 | ==================================================================== |
183 |                                                                      |
184 | Function:  Initialize the signal vector for ALL possible signals     |
185 |            (as defined in /usr/include/sys/signal.h) except for      |
186 |            the following signals which cannot be caught or ignored:  |
187 |                                                                      |
188 |              o  SIGKILL (9)                                          |
189 |              o  SIGSTOP (17)                                         |
190 |              o  SIGCONT (19)                                         |
191 |                                                                      |
192 | Returns:   n/a                                                       |
193 |                                                                      |
194 +---------------------------------------------------------------------*/
init_sig()195 void init_sig()
196 {
197 	struct sigaction invec;
198 	char msg[256];		/* Buffer for error message */
199 	int i;
200 
201 	for (i = 1; i <= SIGMAX; i++) {
202 
203 		/* Cannot catch or ignore the following signals */
204 #ifdef _IA64			/* SIGWAITING not supported, RESERVED */
205 		if ((i == SIGKILL) || (i == SIGSTOP) ||
206 		    (i == SIGCONT) || (i == SIGWAITING))
207 			continue;
208 #else
209 #ifdef _LINUX_
210 		if ((i == SIGKILL) || (i == SIGSTOP)
211 		    || ((i >= 32) && (i <= 34)))
212 			continue;
213 #else
214 		if (i == SIGKILL || i == SIGSTOP || i == SIGCONT)
215 			continue;
216 #endif
217 #endif
218 
219 		invec.sa_handler = (void (*)(int))handler;
220 		sigemptyset(&invec.sa_mask);
221 		invec.sa_flags = 0;
222 
223 		if (sigaction(i, &invec, NULL) < 0) {
224 			sprintf(msg, "sigaction failed on signal %d", i);
225 			error(msg, __LINE__);
226 		}
227 	}
228 }
229 
230 /*---------------------------------------------------------------------+
231 |                             sys_error ()                             |
232 | ==================================================================== |
233 |                                                                      |
234 | Function:  Creates system error message and calls error ()           |
235 |                                                                      |
236 +---------------------------------------------------------------------*/
sys_error(const char * msg,int line)237 void sys_error(const char *msg, int line)
238 {
239 	char syserr_msg[256];
240 
241 	sprintf(syserr_msg, "%s: %s\n", msg, strerror(errno));
242 	error(syserr_msg, line);
243 }
244 
245 /*---------------------------------------------------------------------+
246 |                               error ()                               |
247 | ==================================================================== |
248 |                                                                      |
249 | Function:  Prints out message and exits...                           |
250 |                                                                      |
251 +---------------------------------------------------------------------*/
error(const char * msg,int line)252 void error(const char *msg, int line)
253 {
254 	fprintf(stderr, "ERROR [line: %d] %s\n", line, msg);
255 	exit(-1);
256 }
257