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