1/*
2 *
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/*
21 * Test Name: sigprocmask01
22 *
23 * Test Description:
24 *  Verify that sigprocmask() succeeds to examine and change the calling
25 *  process's signal mask.
26 *  Also, verify that sigpending() succeeds to store signal mask that are
27 *  blocked from delivery and pending for the calling process.
28 *
29 * Expected Result:
30 *  - sigprocmask() should return value 0 on successs and succeed to change
31 *    calling process's set of blocked/unblocked signals.
32 *  - sigpending() should succeed to store the signal mask of pending signal.
33 *
34 * Algorithm:
35 *  Setup:
36 *   Setup signal handling.
37 *   Create temporary directory.
38 *   Pause for SIGUSR1 if option specified.
39 *
40 *  Test:
41 *   Loop if the proper options are given.
42 *   Execute system call
43 *   Check return code, if system call failed (return=-1)
44 *   	Log the errno and Issue a FAIL message.
45 *   Otherwise,
46 *   	Verify the Functionality of system call
47 *      if successful,
48 *      	Issue Functionality-Pass message.
49 *      Otherwise,
50 *		Issue Functionality-Fail message.
51 *  Cleanup:
52 *   Print errno log and/or timing stats if options given
53 *   Delete the temporary directory created.
54 *
55 * Usage:  <for command-line>
56 *  sigprocmask01 [-c n] [-e] [-f] [-i n] [-I x] [-p x] [-t]
57 *	where,  -c n : Run n copies concurrently.
58 *		-e   : Turn on errno logging.
59 *		-f   : Turn off functionality Testing.
60 *		-i n : Execute test n times.
61 *		-I x : Execute test for x seconds.
62 *		-P x : Pause for x seconds between iterations.
63 *		-t   : Turn on syscall timing.
64 *
65 * History
66 *	07/2001 John George
67 *		-Ported
68 *
69 * Restrictions:
70 *  None.
71 */
72
73#include <stdio.h>
74#include <unistd.h>
75#include <sys/types.h>
76#include <errno.h>
77#include <fcntl.h>
78#include <string.h>
79#include <signal.h>
80#include <ucontext.h>
81
82#include "test.h"
83
84void setup();			/* Main setup function of test */
85void cleanup();			/* cleanup function for the test */
86void sig_handler(int sig);	/* signal catching function */
87
88char *TCID = "sigprocmask01";
89int TST_TOTAL = 1;
90
91int sig_catch = 0;		/* variable to blocked/unblocked signals */
92
93struct sigaction sa_new;	/* struct to hold signal info */
94sigset_t set;		/* signal set to hold signal lists */
95sigset_t sigset2;
96
97int main(int ac, char **av)
98{
99	int lc;
100	pid_t my_pid;		/* test process id */
101
102	tst_parse_opts(ac, av, NULL, NULL);
103
104	setup();
105
106	for (lc = 0; TEST_LOOPING(lc); lc++) {
107
108		tst_count = 0;
109
110		/*
111		 * Call sigprocmask() to block (SIGINT) signal
112		 * so that, signal will not be delivered to
113		 * the test process.
114		 */
115		TEST(sigprocmask(SIG_BLOCK, &set, 0));
116
117		/* Get the process id of test process */
118		my_pid = getpid();
119
120		/* Send SIGINT signal to the process */
121		kill(my_pid, SIGINT);
122
123		if (TEST_RETURN == -1) {
124			tst_resm(TFAIL,
125				 "sigprocmask() Failed, errno=%d : %s",
126				 TEST_ERRNO, strerror(TEST_ERRNO));
127		} else {
128			/*
129			 * Check whether process received the signal.
130			 * If yes! signal handler was executed and
131			 * incremented 'sig_catch' variable.
132			 */
133			if (sig_catch) {
134				tst_resm(TFAIL, "sigprocmask fails to "
135					 "change process's signal mask");
136			} else {
137				/*
138				 * Check whether specified signal
139				 * 'SIGINT' is pending for the process.
140				 */
141				errno = 0;
142				if (sigpending(&sigset2) == -1) {
143					tst_brkm(TFAIL, cleanup,
144						 "blocked signal not "
145						 "in pending state, "
146						 "error:%d", errno);
147				}
148
149				/*
150				 * Check whether specified signal
151				 * is the member of signal set.
152				 */
153				errno = 0;
154				if (!sigismember(&sigset2, SIGINT)) {
155					tst_brkm(TFAIL, cleanup,
156						 "sigismember() failed, "
157						 "error:%d", errno);
158				}
159
160				/*
161				 * Invoke sigprocmask() again to
162				 * unblock the specified signal.
163				 * so that, signal is delivered and
164				 * signal handler executed.
165				 */
166				errno = 0;
167				if (sigprocmask(SIG_UNBLOCK,
168						&set, 0) == -1) {
169					tst_brkm(TFAIL, cleanup,
170						 "sigprocmask() failed "
171						 "to unblock signal, "
172						 "error=%d", errno);
173				}
174				if (sig_catch) {
175					tst_resm(TPASS, "Functionality "
176						 "of sigprocmask() "
177						 "Successful");
178				} else {
179					tst_resm(TFAIL, "Functionality "
180						 "of sigprocmask() "
181						 "Failed");
182				}
183				/* set sig_catch back to 0 */
184				sig_catch = 0;
185			}
186		}
187
188		tst_count++;	/* incr TEST_LOOP counter */
189	}
190
191	cleanup();
192	tst_exit();
193}
194
195/*
196 * void
197 * setup() - performs all ONE TIME setup for this test.
198 * Initialise signal set with the list that includes/excludes
199 * all system-defined signals.
200 * Set the signal handler to catch SIGINT signal.
201 * Add the signal SIGINT to the exclude list of system-defined
202 * signals for the test process.
203 */
204void setup(void)
205{
206
207	tst_sig(FORK, DEF_HANDLER, cleanup);
208
209	TEST_PAUSE;
210
211	/*
212	 * Initialise the signal sets with the list that
213	 * excludes/includes  all system-defined signals.
214	 */
215	if (sigemptyset(&set) == -1) {
216		tst_brkm(TFAIL, cleanup,
217			 "sigemptyset() failed, errno=%d : %s",
218			 errno, strerror(errno));
219	}
220	if (sigfillset(&sigset2) == -1) {
221		tst_brkm(TFAIL, cleanup,
222			 "sigfillset() failed, errno=%d : %s",
223			 errno, strerror(errno));
224	}
225
226	/* Set the signal handler function to catch the signal */
227	sa_new.sa_handler = sig_handler;
228	if (sigaction(SIGINT, &sa_new, 0) == -1) {
229		tst_brkm(TFAIL, cleanup,
230			 "sigaction() failed, errno=%d : %s",
231			 errno, strerror(errno));
232	}
233
234	/*
235	 * Add specified signal (SIGINT) to the signal set
236	 * which excludes system-defined signals.
237	 */
238	if (sigaddset(&set, SIGINT) == -1) {
239		tst_brkm(TFAIL, cleanup,
240			 "sigaddset() failed, errno=%d : %s",
241			 errno, strerror(errno));
242	}
243}
244
245/*
246 * void
247 * sig_handler(int sig) - Signal catching function.
248 *   This function gets executed when the signal SIGINT is delivered
249 *   to the test process and the signal was trapped by sigaction()
250 *   to execute this function.
251 *   This function when executed, increments a global variable value
252 *   which will be accessed in the test.
253 */
254void sig_handler(int sig)
255{
256	/* Increment the sig_catch variable */
257	sig_catch++;
258}
259
260/*
261 * void
262 * cleanup() - performs all ONE TIME cleanup for this test at
263 *             completion or premature exit.
264 */
265void cleanup(void)
266{
267
268}
269