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 * NAME
22 * sigaction01.c
23 *
24 * DESCRIPTION
25 * Test some features of sigaction (see below for more details)
26 *
27 * ALGORITHM
28 * Use sigaction(2) to set a signal handler for SIGUSR1 with a certain
29 * set of flags, set a global variable indicating the test case, and
30 * finally send the signal to ourselves, causing the signal handler to
31 * run. The signal handler then checks the signal handler to run. The
32 * signal handler then checks certain conditions based on the test case
33 * number.
34 * There are 4 test cases:
35 *
36 * 1) Set SA_RESETHAND and SA_SIGINFO. When the handler runs,
37 * SA_SIGINFO should be set.
38 *
39 * 2) Set SA_RESETHAND. When the handler runs, SIGUSR1 should be
40 * masked (SA_RESETHAND makes sigaction behave as if SA_NODEFER was
41 * not set).
42 *
43 * 3) Same as case #2, but when the handler is established, sa_mask is
44 * set to include SIGUSR1. Ensure that SIGUSR1 is indeed masked even if
45 * SA_RESETHAND is set.
46 *
47 * 4) A signal generated from an interface or condition that does not
48 * provide siginfo (such as pthread_kill(3)) should invoke the handler
49 * with a non-NULL siginfo pointer.
50 *
51 * USAGE: <for command-line>
52 * sigaction01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
53 * where, -c n : Run n copies concurrently.
54 * -f : Turn off functionality Testing.
55 * -i n : Execute test n times.
56 * -I x : Execute test for x seconds.
57 * -P x : Pause for x seconds between iterations.
58 * -t : Turn on syscall timing.
59 *
60 * HISTORY
61 * 07/2001 Ported by Wayne Boyer
62 *
63 * RESTRICTIONS
64 * NONE
65 */
66 #include <pthread.h>
67 #include <signal.h>
68 #include <errno.h>
69 #include <stdlib.h>
70 #include <unistd.h>
71 #include "test.h"
72
73 void setup();
74 void cleanup();
75
76 char *TCID = "sigaction01";
77 int TST_TOTAL = 4;
78
79 volatile sig_atomic_t testcase_no;
80 volatile sig_atomic_t pass;
81
82 /*
83 * handler()
84 *
85 * A signal handler that understands which test case is currently
86 * being executed and compares the current conditions to the ones it
87 * expects (based on the test case number).
88 */
handler(int sig,siginfo_t * sip,void * ucp)89 void handler(int sig, siginfo_t * sip, void *ucp)
90 {
91 struct sigaction oact;
92 int err;
93 sigset_t nmask, omask;
94
95 /*
96 * Get sigaction setting
97 */
98 err = sigaction(SIGUSR1, NULL, &oact);
99
100 if (err == -1) {
101 perror("sigaction");
102 return;
103 }
104
105 /*
106 * Get current signal mask
107 */
108 sigemptyset(&nmask);
109 sigemptyset(&omask);
110 err = sigprocmask(SIG_BLOCK, &nmask, &omask);
111 if (err == -1) {
112 perror("sigprocmask");
113 tst_resm(TWARN, "sigprocmask() failed");
114 return;
115 }
116
117 switch (testcase_no) {
118 case 1:
119 /*
120 * SA_RESETHAND and SA_SIGINFO were set. SA_SIGINFO should
121 * be clear in Linux. In Linux kernel, SA_SIGINFO is not
122 * cleared in psig().
123 */
124 if (!(oact.sa_flags & SA_SIGINFO)) {
125 tst_resm(TFAIL, "SA_RESETHAND should not "
126 "cause SA_SIGINFO to be cleared, but it was.");
127 return;
128 }
129 if (sip == NULL) {
130 tst_resm(TFAIL, "siginfo should not be NULL");
131 return;
132 }
133 tst_resm(TPASS, "SA_RESETHAND did not "
134 "cause SA_SIGINFO to be cleared");
135 break;
136
137 case 2:
138 /*
139 * In Linux, SA_RESETHAND doesn't imply SA_NODEFER; sig
140 * should not be masked. The testcase should pass if
141 * SA_NODEFER is not masked, ie. if SA_NODEFER is a member
142 * of the signal list
143 */
144 if (sigismember(&omask, sig) == 0) {
145 tst_resm(TFAIL, "SA_RESETHAND should cause sig to"
146 "be masked when the handler executes.");
147 return;
148 }
149 tst_resm(TPASS, "SA_RESETHAND was masked when handler "
150 "executed");
151 break;
152
153 case 3:
154 /*
155 * SA_RESETHAND implies SA_NODEFER unless sa_mask already
156 * included sig.
157 */
158 if (!sigismember(&omask, sig)) {
159 tst_resm(TFAIL, "sig should continue to be masked"
160 "because sa_mask originally contained sig.");
161 return;
162 }
163 tst_resm(TPASS, "sig has been masked "
164 "because sa_mask originally contained sig");
165 break;
166
167 case 4:
168 /*
169 * A signal generated from a mechanism that does not provide
170 * siginfo should invoke the handler with a non-NULL siginfo
171 * pointer.
172 */
173 if (sip == NULL) {
174 tst_resm(TFAIL, "siginfo pointer should not be NULL");
175 return;
176 }
177 tst_resm(TPASS, "siginfo pointer non NULL");
178 break;
179
180 default:
181 tst_resm(TFAIL, "invalid test case number: %d", testcase_no);
182 exit(1);
183 }
184 }
185
186 /*
187 * set_handler()
188 *
189 * Establish a signal handler for SIGUSR1 with the specified flags and
190 * signal to mask while the handler executes.
191 */
set_handler(int flags,int sig_to_mask)192 int set_handler(int flags, int sig_to_mask)
193 {
194 struct sigaction sa;
195
196 sa.sa_sigaction = handler;
197 sa.sa_flags = flags;
198 sigemptyset(&sa.sa_mask);
199 sigaddset(&sa.sa_mask, sig_to_mask);
200
201 TEST(sigaction(SIGUSR1, &sa, NULL));
202 if (TEST_RETURN != 0) {
203 perror("sigaction");
204 tst_resm(TFAIL, "call failed unexpectedly");
205 return 1;
206 }
207 return 0;
208 }
209
210 /*
211 * setup() - performs all ONE TIME setup for this test.
212 */
setup(void)213 void setup(void)
214 {
215
216 TEST_PAUSE;
217 }
218
219 /*
220 * cleanup() - performs all ONE TIME cleanup for this test at
221 * completion or premature exit.
222 */
cleanup(void)223 void cleanup(void)
224 {
225
226 }
227
main(int ac,char ** av)228 int main(int ac, char **av)
229 {
230 int lc;
231 int i;
232 int test_flags[] = { SA_RESETHAND | SA_SIGINFO, SA_RESETHAND,
233 SA_RESETHAND | SA_SIGINFO, SA_RESETHAND | SA_SIGINFO
234 };
235
236 tst_parse_opts(ac, av, NULL, NULL);
237
238 setup();
239
240 for (lc = 0; TEST_LOOPING(lc); lc++) {
241
242 /* reset tst_count in case we are looping */
243 tst_count = 0;
244
245 testcase_no = 0;
246
247 for (i = 0; i < TST_TOTAL; i++) {
248 if (set_handler(test_flags[i], 0) == 0) {
249 testcase_no++;
250 switch (i) {
251 case 0:
252 /*FALLTHROUGH*/ case 1:
253 (void)kill(getpid(), SIGUSR1);
254 break;
255 case 2:
256 /*FALLTHROUGH*/ case 3:
257 (void)
258 pthread_kill(pthread_self(),
259 SIGUSR1);
260 break;
261 default:
262 tst_brkm(TBROK, cleanup,
263 "illegal case number");
264 break;
265 }
266 }
267 }
268 }
269
270 cleanup();
271 tst_exit();
272 }
273