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