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: sigsuspend01
22  *
23  * Test Description:
24  *  Verify that sigsuspend() succeeds to change process's current signal
25  *  mask with the specified signal mask and suspends the process execution
26  *  until the delivery of a signal.
27  *
28  * Expected Result:
29  *  sigsuspend() should return after the execution of signal catching
30  *  function and the previous signal mask should be restored.
31  *
32  * Algorithm:
33  *  Setup:
34  *   Setup signal handling.
35  *   Create temporary directory.
36  *   Pause for SIGUSR1 if option specified.
37  *
38  *  Test:
39  *   Loop if the proper options are given.
40  *   Execute system call
41  *   Check return code, if system call failed (return=-1)
42  *   	Log the errno and Issue a FAIL message.
43  *   Otherwise,
44  *   	Verify the Functionality of system call
45  *      if successful,
46  *      	Issue Functionality-Pass message.
47  *      Otherwise,
48  *		Issue Functionality-Fail message.
49  *  Cleanup:
50  *   Print errno log and/or timing stats if options given
51  *   Delete the temporary directory created.
52  *
53  * Usage:  <for command-line>
54  *  sigsuspend01 [-c n] [-e] [-f] [-i n] [-I x] [-p x] [-t]
55  *	where,  -c n : Run n copies concurrently.
56  *		-e   : Turn on errno logging.
57  *		-f   : Turn off functionality Testing.
58  *		-i n : Execute test n times.
59  *		-I x : Execute test for x seconds.
60  *		-P x : Pause for x seconds between iterations.
61  *		-t   : Turn on syscall timing.
62  *
63  * History
64  *	07/2001 John George
65  *		-Ported
66  *
67  * Restrictions:
68  *  None.
69  */
70 
71 #include <stdio.h>
72 #include <unistd.h>
73 #include <sys/types.h>
74 #include <errno.h>
75 #include <fcntl.h>
76 #include <string.h>
77 #include <signal.h>
78 #include <ucontext.h>
79 
80 #include "test.h"
81 
82 char *TCID = "sigsuspend01";
83 int TST_TOTAL = 1;
84 
85 struct sigaction sa_new;	/* struct to hold signal info */
86 sigset_t signalset;		/* signal set to hold signal lists */
87 sigset_t sigset1;
88 sigset_t sigset2;
89 
90 void setup();			/* Main setup function of test */
91 void cleanup();			/* cleanup function for the test */
92 void sig_handler(int sig);	/* signal catching function */
93 
94 int main(int ac, char **av)
95 {
96 	int lc;
97 
98 	tst_parse_opts(ac, av, NULL, NULL);
99 
100 	setup();
101 
102 	for (lc = 0; TEST_LOOPING(lc); lc++) {
103 
104 		tst_count = 0;
105 
106 		/* Set the alarm timer */
107 		alarm(5);
108 
109 		/*
110 		 * Call sigsuspend() to replace current signal mask
111 		 * of the process and suspend process execution till
112 		 * receipt of a signal 'SIGALRM'.
113 		 */
114 		TEST(sigsuspend(&signalset));
115 
116 		/* Reset the alarm timer */
117 		alarm(0);
118 
119 		if ((TEST_RETURN == -1) && (TEST_ERRNO == EINTR)) {
120 			if (sigprocmask(SIG_UNBLOCK, 0, &sigset2) == -1) {
121 				tst_resm(TFAIL, "sigprocmask() Failed "
122 					 "to get previous signal mask "
123 					 "of process");
124 			} else if (sigset2.__val[0] != sigset1.__val[0]) {
125 				tst_resm(TFAIL, "sigsuspend failed to "
126 					 "preserve signal mask");
127 			} else {
128 				tst_resm(TPASS, "Functionality of "
129 					 "sigsuspend() successful");
130 			}
131 		} else {
132 			tst_resm(TFAIL | TTERRNO,
133 				 "sigsuspend() returned value %ld",
134 				 TEST_RETURN);
135 		}
136 
137 		tst_count++;	/* incr TEST_LOOP counter */
138 	}
139 
140 	cleanup();
141 	tst_exit();
142 }
143 
144 /*
145  * void
146  * setup() - performs all ONE TIME setup for this test.
147  * Initialise signal set with the list that includes/excludes
148  * all system-defined signals.
149  * Set the signal handler to catch SIGALRM signal.
150  * Get the current signal mask of test process using sigprocmask().
151  */
152 void setup(void)
153 {
154 
155 	tst_sig(FORK, DEF_HANDLER, cleanup);
156 
157 	TEST_PAUSE;
158 
159 	/*
160 	 * Initialise the signal sets with the list that
161 	 * excludes/includes  all system-defined signals.
162 	 */
163 	if (sigemptyset(&signalset) == -1) {
164 		tst_brkm(TFAIL, cleanup,
165 			 "sigemptyset() failed, errno=%d : %s",
166 			 errno, strerror(errno));
167 	}
168 	if (sigfillset(&sigset2) == -1) {
169 		tst_brkm(TFAIL, cleanup,
170 			 "sigfillset() failed, errno=%d : %s",
171 			 errno, strerror(errno));
172 	}
173 
174 	/* Set the signal handler function to catch the signal */
175 	sa_new.sa_handler = sig_handler;
176 	if (sigaction(SIGALRM, &sa_new, 0) == -1) {
177 		tst_brkm(TFAIL, cleanup,
178 			 "sigaction() failed, errno=%d : %s",
179 			 errno, strerror(errno));
180 	}
181 
182 	/* Read the test process's current signal mask. */
183 	if (sigprocmask(SIG_UNBLOCK, 0, &sigset1) == -1) {
184 		tst_brkm(TFAIL, cleanup,
185 			 "sigprocmask() Failed, errno=%d : %s",
186 			 errno, strerror(errno));
187 	}
188 }
189 
190 /*
191  * void
192  * sig_handler(int sig) - Signal catching function.
193  *   This function gets executed when the signal SIGALRM is delivered
194  *   to the test process after the expiry of alarm time and the signal was
195  *   trapped by sigaction() to execute this function.
196  *
197  *   This function simply returns without doing anything.
198  */
199 void sig_handler(int sig)
200 {
201 }
202 
203 /*
204  * void
205  * cleanup() - performs all ONE TIME cleanup for this test at
206  *             completion or premature exit.
207  */
208 void cleanup(void)
209 {
210 
211 }
212