1/*
2 * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
3 *  AUTHOR           :  Dave Baumgartner
4 *                   :  Rewrote 12/92 by Richard Logan
5 *  CO-PILOT         :  Barrie Kletscher
6 *  DATE STARTED     :  10/17/85
7 * Copyright (C) 2015 Cyril Hrubis <chrubis@suse.cz>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of version 2 of the GNU General Public License as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it would be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * Further, this software is distributed without any warranty that it is
18 * free of the rightful claim of any third person regarding infringement
19 * or the like.  Any license provided herein, whether implied or
20 * otherwise, applies only to this software file.  Patent licenses, if
21 * any, provided herein do not apply to combinations of this program with
22 * other software, or any other product whatsoever.
23 *
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write the Free Software Foundation, Inc.,
26 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 *
28 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
29 * Mountain View, CA  94043, or:
30 *
31 * http://www.sgi.com
32 *
33 * For further information regarding this notice, see:
34 *
35 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
36 *
37 */
38/*
39 * TEST ITEMS
40 *
41 *	1. SIGKILL can not be set to be caught, errno:EINVAL (POSIX).
42 *	2. SIGKILL can not be caught.
43 *	3. SIGKILL can not be set to be ignored, errno:EINVAL (POSIX).
44 *	4. SIGKILL can not be ignored.
45 *	5. SIGKILL can not be reset to default, errno:EINVAL (POSIX).
46 */
47#include <signal.h>
48#include <errno.h>
49#include <unistd.h>
50#include <fcntl.h>
51#include <string.h>
52#include <stdlib.h>
53#include <sys/wait.h>
54
55#include "test.h"
56#include "safe_macros.h"
57
58static void setup(void);
59static void do_test(int tc);
60static void do_child(void);
61static void catchsig(int sig);
62
63static struct tcase {
64	void (*sighandler)(int);
65	int kill;
66} tcases[] = {
67	{SIG_IGN, 0},
68	{SIG_DFL, 0},
69	{catchsig, 0},
70	{SIG_IGN, 1},
71	{SIG_DFL, 1},
72	{catchsig, 1},
73};
74
75char *TCID = "signal01";
76int TST_TOTAL = ARRAY_SIZE(tcases);
77
78static int tcase;
79
80int main(int argc, char *argv[])
81{
82	int lc, i;
83
84	tst_parse_opts(argc, argv, NULL, NULL);
85
86#ifdef UCLINUX
87	maybe_run_child(&do_child, "d", &tcase);
88#endif
89
90	setup();
91
92	for (lc = 0; TEST_LOOPING(lc); lc++) {
93		for (i = 0; i < TST_TOTAL; i++)
94			do_test(i);
95	}
96
97	tst_exit();
98}
99
100static void do_test(int tc)
101{
102	pid_t pid;
103	int res;
104	pid = FORK_OR_VFORK();
105
106	switch (pid) {
107	case 0:
108#ifdef UCLINUX
109		if (self_exec(argv0, "d", tc) < 0)
110			tst_brkm(TBROK | TERRNO, NULL, "self_exec() failed");
111#else
112		tcase = tc;
113		do_child();
114#endif
115	break;
116	case -1:
117		tst_resm(TBROK | TERRNO, "fork() failed");
118	break;
119	default:
120		if (tcases[tc].kill) {
121			TST_PROCESS_STATE_WAIT(NULL, pid, 'S');
122
123			SAFE_KILL(NULL, pid, SIGKILL);
124
125			SAFE_WAITPID(NULL, pid, &res, 0);
126
127			if (WIFSIGNALED(res)) {
128				if (WTERMSIG(res) == SIGKILL) {
129					tst_resm(TPASS, "Child killed with SIGKILL");
130				} else {
131					tst_resm(TFAIL, "Child killed with %s",
132					         tst_strsig(WTERMSIG(res)));
133				}
134			} else {
135				tst_resm(TFAIL, "Child not killed by signal");
136			}
137		} else {
138			tst_record_childstatus(NULL, pid);
139		}
140	break;
141	}
142}
143
144static void catchsig(int sig)
145{
146	(void)sig;
147}
148
149static const char *strhandler(void *sighandler)
150{
151	switch ((long)sighandler) {
152	case (long)SIG_DFL:
153		return "SIG_DFL";
154	case (long)SIG_IGN:
155		return "SIG_IGN";
156	default:
157		return "catchsig()";
158	}
159}
160
161static void do_child(void)
162{
163	void *ret;
164	void (*sighandler)(int) = tcases[tcase].sighandler;
165
166	ret = signal(SIGKILL, sighandler);
167
168	if (tcases[tcase].kill)
169		pause();
170
171	if (ret == SIG_ERR || errno == EINVAL) {
172		tst_resm(TPASS, "signal(SIGKILL, %p(%s)) failed with EINVAL",
173		         sighandler, strhandler(sighandler));
174	} else {
175		if (ret != SIG_ERR) {
176			tst_resm(TFAIL, "signal(SIGKILL, %p(%s)) didn't fail",
177			         sighandler, strhandler(sighandler));
178		} else {
179			tst_resm(TFAIL | TERRNO,
180			         "signal(SIGKILL, %p(%s)) should fail with EINVAL",
181			          sighandler, strhandler(sighandler));
182		}
183	}
184
185	tst_exit();
186}
187
188static void setup(void)
189{
190	tst_sig(FORK, DEF_HANDLER, NULL);
191
192	TEST_PAUSE;
193}
194