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_05                            |
21 | ==================================================================== |
22 |                                                                      |
23 | Description:  Verify that signals can be ignored by the receiving    |
24 |               process.                                               |
25 |                                                                      |
26 | Algorithm:    o  Spawn a child                                       |
27 |                                                                      |
28 |               (parent)                                               |
29 |               o  Use sigaction (SIG_IGN) to ignore all catchable     |
30 |                  signals from child, except for sigchild             |
31 |               o  Wait until sigchld signal is received               |
32 |               o  Verify that the sigchild interrupt was received     |
33 |               o  Additionally check to verify that child process     |
34 |                  exited successfully                                 |
35 |                                                                      |
36 |               (child)                                                |
37 |               o  Send all catchable signals to the parent            |
38 |               o  exit (implicitly send sigchild signal to parent)    |
39 |                                                                      |
40 |                                                                      |
41 | System calls: The following system calls are tested:                 |
42 |                                                                      |
43 |               sigaction () - Specify the action to take upon         |
44 |                              delivery of a signal                    |
45 |               wait () - Waits for a child process to stop or         |
46 |                         terminate                                    |
47 |               kill () - Sends a signal to a process                  |
48 |                                                                      |
49 | Usage:        signal_test_05                                         |
50 |                                                                      |
51 | To compile:   cc -o signal_test_05 signal_test_05                    |
52 |                                                                      |
53 | Last update:   Ver. 1.2, 2/7/94 23:24:05                           |
54 |                                                                      |
55 | Change Activity                                                      |
56 |                                                                      |
57 |   Version  Date    Name  Reason                                      |
58 |    0.1     050689  CTU   Initial version                             |
59 |    0.2     112993  DJK   Rewrite for AIX version 4.1                 |
60 |    1.2     020794  DJK   Move to "prod" directory                    |
61 |                                                                      |
62 +---------------------------------------------------------------------*/
63 
64 #include <stdio.h>
65 #include <string.h>
66 #ifdef _LINUX_
67 #define __USE_XOPEN
68 #include <sys/types.h>
69 #include <sys/stat.h>
70 #endif
71 #include <unistd.h>
72 #include <sys/signal.h>
73 #include <sys/wait.h>
74 #include <stdlib.h>
75 #include <errno.h>
76 
77 #ifdef _LINUX_
78 // bits/signum.h defines _NSIG as 64
79 #define SIGMAX 64
80 #endif
81 
82 /* Function prototypes */
83 void ignore_signals();
84 void child(int);
85 void handler(int, int, struct sigcontext *);
86 void sys_error(const char *, int);
87 void error(const char *, int);
88 
89 /* Flag set upon receiving SIGCHLD signal */
90 int sigchld_flag = 0;
91 
92 /*---------------------------------------------------------------------+
93 |                               main ()                                |
94 | ==================================================================== |
95 |                                                                      |
96 | Function:  Main program  (see prolog for more details)               |
97 |                                                                      |
98 +---------------------------------------------------------------------*/
main(int argc,char ** argv)99 int main(int argc, char **argv)
100 {
101 
102 	pid_t pid = getpid();	/* Process ID (of parent process) */
103 	int status;		/* Child's exit status */
104 
105 	/* Print out program header */
106 	printf("%s: IPC TestSuite program\n\n", *argv);
107 
108 	/* Set up our signal handler */
109 	ignore_signals();
110 
111 	/*
112 	 * Spawn a child process & have the child process send all of the
113 	 * catchable signals to the parent.
114 	 */
115 	printf("\n\tSpawning child process\n");
116 	switch (fork()) {
117 	case -1:		/* Unable to create child process */
118 		sys_error("fork failed", __LINE__);
119 
120 	case 0:		/* Child process */
121 		child(pid);
122 
123 	default:		/* Parent process */
124 		break;
125 	}
126 
127 	/*
128 	 * Wait for the child process to complete
129 	 *
130 	 * Suspend execution of the parent process until either a signal
131 	 * that is not blocked or ignored, or until the child process
132 	 * completes.
133 	 *
134 	 * Use the POSIX macro to insure that the child process exited
135 	 * normally.
136 	 *
137 	 * Check to insure that the SIGCHLD signal was caught.
138 	 */
139 	wait(&status);
140 
141 	if (!WIFEXITED(status))
142 		error("child process exited abnormally", __LINE__);
143 
144 	if (sigchld_flag != 1)
145 		error("child process failed to send SIGCHLD signal", __LINE__);
146 
147 	printf("\n\tChild process exited successfully\n");
148 
149 	/* Program completed successfully -- exit */
150 	printf("\nsuccessful!\n");
151 
152 	return 0;
153 }
154 
155 /*---------------------------------------------------------------------+
156 |                               child ()                               |
157 | ==================================================================== |
158 |                                                                      |
159 | Function:  Child process                                             |
160 |            o  Send all catchable signals (except sigchild) to parent |
161 |            o  exit & implicitly send sigchild signal to parent       |
162 |                                                                      |
163 | Parms:     pid - process id of parent process                        |
164 |                                                                      |
165 +---------------------------------------------------------------------*/
child(pid_t pid)166 void child(pid_t pid)
167 {
168 	int i;
169 
170 	/* Send one of each of the possible signals to the process */
171 	printf("\n\tChild: sending ALL signals to parent!\n");
172 	for (i = 1; i < (SIGMAX + 1); i++) {
173 
174 		/* Cannot catch or ignore the following signals */
175 #ifdef _LINUX_
176 		if ((i == SIGKILL) || (i == SIGSTOP)
177 		    || ((i >= 32) && (i <= 34)))
178 			continue;
179 #else
180 		if (i == SIGKILL || i == SIGSTOP || i == SIGCONT)
181 			continue;
182 #endif
183 
184 		/* Skip sigchild too */
185 		if (i == SIGCHLD)
186 			continue;
187 #ifdef _IA64
188 		/* RESERVED - DON'T USE */
189 		if (i == SIGWAITING)
190 			continue;
191 #endif
192 
193 		printf("\tSending (%d)\n", i);
194 
195 		if (kill(pid, i) < 0)
196 			sys_error("kill failed", __LINE__);
197 	}
198 
199 	/* Exit & implicitly send a sigchild interrupt to the parent process */
200 	exit(0);
201 }
202 
203 /*---------------------------------------------------------------------+
204 |                               handler ()                             |
205 | ==================================================================== |
206 |                                                                      |
207 | Function:  Signal handler                                            |
208 |            o  Send all catchable signals (except sigchild) to parent |
209 |                                                                      |
210 | Parms:     signal - signal number caught                             |
211 |                                                                      |
212 | Returns:   Aborts if an unexpected signal is caught                  |
213 |                                                                      |
214 +---------------------------------------------------------------------*/
handler(int signal,int code,struct sigcontext * scp)215 void handler(int signal, int code, struct sigcontext *scp)
216 {
217 	char msg[100];
218 
219 	if (signal == SIGCHLD) {
220 		printf("\tcaught SIGCHLD(%d) signal\n", signal);
221 		sigchld_flag = 1;
222 	} else {
223 		sprintf(msg, "caught an unexpected signal (%d)", signal);
224 		error(msg, __LINE__);
225 	}
226 }
227 
228 /*---------------------------------------------------------------------+
229 |                           ignore_signals ()                          |
230 | ==================================================================== |
231 |                                                                      |
232 | Function:  Force all signals to be ignored, except for the following |
233 |            signals:                                                  |
234 |                                                                      |
235 |            (Sent when child process stops or exits)                  |
236 |                                                                      |
237 |              o  SIGCHLD (20)                                         |
238 |                                                                      |
239 |            (Theses cannot be caught or ignored)                      |
240 |                                                                      |
241 |              o  SIGKILL (9)                                          |
242 |              o  SIGSTOP (17)                                         |
243 |              o  SIGCONT (19)                                         |
244 |                                                                      |
245 | Returns:   n/a                                                       |
246 |                                                                      |
247 +---------------------------------------------------------------------*/
ignore_signals()248 void ignore_signals()
249 {
250 	struct sigaction action;
251 	char msg[100];
252 	int i;
253 
254 	for (i = 1; i < (SIGMAX + 1); i++) {
255 
256 		/* Cannot catch or ignore the following signals: */
257 #ifdef _LINUX_
258 		if ((i == SIGKILL) || (i == SIGSTOP)
259 		    || ((i >= 32) && (i <= 34)))
260 			continue;
261 #else
262 		if (i == SIGKILL || i == SIGSTOP || i == SIGCONT)
263 			continue;
264 #endif
265 
266 		/* Do not ignore SIGCHILD signal */
267 		if (i == SIGCHLD)
268 			continue;
269 
270 		action.sa_handler = SIG_IGN;
271 		sigfillset(&action.sa_mask);
272 		action.sa_flags = SA_RESTART;
273 
274 		if (sigaction(i, &action, NULL) < 0) {
275 			perror("ignore_signals: sigaction");
276 			sprintf(msg, "sigaction failed on signal %d", i);
277 			error(msg, __LINE__);
278 		}
279 	}
280 
281 	/* Setup signal handler for SIGCHLD signal */
282 	action.sa_handler = (void (*)(int))handler;
283 	sigfillset(&action.sa_mask);
284 	action.sa_flags = SA_RESTART;
285 	if (sigaction(SIGCHLD, &action, NULL) < 0)
286 		sys_error("sigaction (SIGCHLD) failed", __LINE__);
287 }
288 
289 /*---------------------------------------------------------------------+
290 |                             sys_error ()                             |
291 | ==================================================================== |
292 |                                                                      |
293 | Function:  Creates system error message and calls error ()           |
294 |                                                                      |
295 +---------------------------------------------------------------------*/
sys_error(const char * msg,int line)296 void sys_error(const char *msg, int line)
297 {
298 	char syserr_msg[256];
299 
300 	sprintf(syserr_msg, "%s: %s\n", msg, strerror(errno));
301 	error(syserr_msg, line);
302 }
303 
304 /*---------------------------------------------------------------------+
305 |                               error ()                               |
306 | ==================================================================== |
307 |                                                                      |
308 | Function:  Prints out message and exits...                           |
309 |                                                                      |
310 +---------------------------------------------------------------------*/
error(const char * msg,int line)311 void error(const char *msg, int line)
312 {
313 	fprintf(stderr, "ERROR [line: %d] %s\n", line, msg);
314 	exit(-1);
315 }
316