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: sigalstack01
22 *
23 * Test Description:
24 *  Send a signal using the main stack. While executing the signal handler
25 *  compare a variable's address lying on the main stack with the stack
26 *  boundaries returned by sigaltstack().
27 *
28 * Expected Result:
29 *  sigaltstack() should succeed to get/set signal alternate stack context.
30 *
31 * Algorithm:
32 *  Setup:
33 *   Setup signal handling.
34 *   Pause for SIGUSR1 if option specified.
35 *
36 *  Test:
37 *   Loop if the proper options are given.
38 *   Execute system call
39 *   Check return code, if system call failed (return=-1)
40 *	Log the errno and Issue a FAIL message.
41 *   Otherwise,
42 *	Verify the Functionality of system call
43 *      if successful,
44 *		Issue Functionality-Pass message.
45 *      Otherwise,
46 *		Issue Functionality-Fail message.
47 *  Cleanup:
48 *   Print errno log and/or timing stats if options given
49 *
50 * Usage:  <for command-line>
51 *  sigaltstack01 [-c n] [-e] [-f] [-i n] [-I x] [-p x] [-t]
52 *	where,  -c n : Run n copies concurrently.
53 *		-e   : Turn on errno logging.
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 John George
62 *		-Ported
63 *
64 * Restrictions:
65 *  This test should be run by 'super-user' (root) only and must run from
66 *  shell which sets up for test.
67 *
68 */
69
70#include <stdio.h>
71#include <sys/types.h>
72#include <unistd.h>
73#include <signal.h>
74#include <string.h>
75#include <ucontext.h>
76#include <errno.h>
77
78#include "test.h"
79
80char *TCID = "sigaltstack01";
81int TST_TOTAL = 1;
82
83void *addr, *main_stk;		/* address of main stack for signal */
84int got_signal = 0;
85pid_t my_pid;			/* test process id */
86
87stack_t sigstk, osigstk;	/* signal stack storing struct. */
88struct sigaction act, oact;	/* sigaction() struct. */
89
90void setup(void);		/* Main setup function of test */
91void cleanup(void);		/* cleanup function for the test */
92void sig_handler(int);		/* signal catching function */
93
94int main(int ac, char **av)
95{
96	int lc;
97	void *alt_stk;		/* address of alternate stack for signal */
98
99	tst_parse_opts(ac, av, NULL, NULL);
100
101	setup();
102
103	for (lc = 0; TEST_LOOPING(lc); lc++) {
104
105		tst_count = 0;
106
107		/* Call sigaltstack() to set up an alternate stack */
108		sigstk.ss_size = SIGSTKSZ;
109		sigstk.ss_flags = 0;
110		TEST(sigaltstack(&sigstk, &osigstk));
111
112		if (TEST_RETURN == -1) {
113			tst_resm(TFAIL,
114				 "sigaltstack() Failed, errno=%d : %s",
115				 TEST_ERRNO, strerror(TEST_ERRNO));
116		} else {
117			/* Set up the signal handler for 'SIGUSR1' */
118			act.sa_flags = SA_ONSTACK;
119			act.sa_handler = (void (*)())sig_handler;
120			if ((sigaction(SIGUSR1, &act, &oact)) == -1) {
121				tst_brkm(TFAIL, cleanup, "sigaction() "
122					 "fails to trap signal "
123					 "delivered on alt. stack, "
124					 "error=%d", errno);
125			}
126
127			/* Deliver signal onto the alternate stack */
128			kill(my_pid, SIGUSR1);
129
130			/* wait till the signal arrives */
131			while (!got_signal) ;
132
133			got_signal = 0;
134			alt_stk = addr;
135
136			/*
137			 * First,
138			 * Check that alt_stk is within the
139			 * alternate stk boundaries
140			 *
141			 * Second,
142			 * Check that main_stk is outside the
143			 * alternate stk boundaries.
144			 */
145			if ((alt_stk < sigstk.ss_sp) &&
146			    (alt_stk > (sigstk.ss_sp + SIGSTKSZ))) {
147				tst_resm(TFAIL,
148					 "alt. stack is not within the "
149					 "alternate stk boundaries");
150			} else if ((main_stk >= sigstk.ss_sp) &&
151				   (main_stk <=
152				    (sigstk.ss_sp + SIGSTKSZ))) {
153				tst_resm(TFAIL,
154					 "main stk. not outside the "
155					 "alt. stack boundaries");
156			} else {
157				tst_resm(TPASS,
158					 "Functionality of "
159					 "sigaltstack() successful");
160			}
161		}
162		tst_count++;	/* incr. TEST_LOOP counter */
163	}
164
165	cleanup();
166	tst_exit();
167}
168
169/*
170 * void
171 * setup() - performs all ONE TIME setup for this test.
172 * Capture SIGUSR1 on the main stack.
173 * send the signal 'SIGUSER1' to the process.
174 * wait till the signal arrives.
175 * Allocate memory for the alternative stack.
176 */
177void setup(void)
178{
179
180	tst_sig(FORK, DEF_HANDLER, cleanup);
181
182	TEST_PAUSE;
183
184	/* Get the process id of test process */
185	my_pid = getpid();
186
187	/* Capture SIGUSR1 on the main stack */
188	act.sa_handler = (void (*)(int))sig_handler;
189	if ((sigaction(SIGUSR1, &act, &oact)) == -1) {
190		tst_brkm(TFAIL, cleanup,
191			 "sigaction() fails in setup, errno=%d", errno);
192	}
193
194	/* Send the signal to the test process */
195	kill(my_pid, SIGUSR1);
196
197	/* Wait till the signal arrives */
198	while (!got_signal) ;
199
200	got_signal = 0;
201	main_stk = addr;
202
203	/* Allocate memory for the alternate stack */
204	if ((sigstk.ss_sp = malloc(SIGSTKSZ)) == NULL) {
205		tst_brkm(TFAIL, cleanup,
206			 "could not allocate memory for the alternate stack");
207	}
208}
209
210/*
211 * void
212 * sig_handler() - signal catching function.
213 *  This functions is called when the signal 'SIGUSR1' is delivered to
214 *  the test process and trapped by sigaction().
215 *
216 *  This function updates 'addr' variable and sets got_signal value.
217 */
218void sig_handler(int n)
219{
220	int i;
221
222	(void) n;
223	addr = &i;
224	got_signal = 1;
225}
226
227/*
228 * void
229 * cleanup() - performs all ONE TIME cleanup for this test at
230 *             completion or premature exit.
231 *  Free the memory allocated for alternate stack.
232 */
233void cleanup(void)
234{
235
236	free(sigstk.ss_sp);
237
238}
239