1/* Tests for posix_spawn signal handling.
2 Copyright (C) 2023-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library 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 the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19#include <assert.h>
20#include <getopt.h>
21#include <spawn.h>
22#include <stdlib.h>
23#include <string.h>
24#include <support/check.h>
25#include <support/xsignal.h>
26#include <support/xunistd.h>
27#include <sys/wait.h>
28#include <unistd.h>
29#include <tst-spawn.h>
30
31/* Nonzero if the program gets called via `exec'. */
32#define CMDLINE_OPTIONS \
33 { "restart", no_argument, &restart, 1 },
34static int restart;
35
36/* Hold the four initial argument used to respawn the process, plus the extra
37 '--direct', '--restart', the check type ('SIG_IGN' or 'SIG_DFL'), and a
38 final NULL. */
39static char *spargs[8];
40static int check_type_argc;
41
42/* Called on process re-execution. */
43_Noreturn static void
44handle_restart (int argc, char *argv[])
45{
46 assert (argc == 1);
47
48 if (strcmp (argv[0], "SIG_DFL") == 0)
49 {
50 for (int i = 1; i < NSIG; i++)
51 {
52 struct sigaction sa;
53 int r = sigaction (sig: i, NULL, oact: &sa);
54 /* Skip internal signals (such as SIGCANCEL). */
55 if (r == -1)
56 continue;
57 TEST_VERIFY_EXIT (sa.sa_handler == SIG_DFL);
58 }
59 exit (EXIT_SUCCESS);
60 }
61 else if (strcmp (argv[0], "SIG_IGN") == 0)
62 {
63 for (int i = 1; i < NSIG; i++)
64 {
65 struct sigaction sa;
66 int r = sigaction (sig: i, NULL, oact: &sa);
67 /* Skip internal signals (such as SIGCANCEL). */
68 if (r == -1)
69 continue;
70 if (i == SIGUSR1 || i == SIGUSR2)
71 TEST_VERIFY_EXIT (sa.sa_handler == SIG_IGN);
72 else
73 TEST_VERIFY_EXIT (sa.sa_handler == SIG_DFL);
74 }
75 exit (EXIT_SUCCESS);
76 }
77
78 exit (EXIT_FAILURE);
79}
80
81static void
82spawn_signal_test (const char *type, const posix_spawnattr_t *attr)
83{
84 spargs[check_type_argc] = (char*) type;
85
86 PID_T_TYPE pid;
87 siginfo_t sinfo;
88
89 TEST_COMPARE (POSIX_SPAWN (&pid, spargs[0], NULL, attr, spargs, environ), 0);
90 TEST_COMPARE (WAITID (P_ALL, 0, &sinfo, WEXITED), 0);
91 TEST_COMPARE (sinfo.si_code, CLD_EXITED);
92 TEST_COMPARE (sinfo.si_status, 0);
93}
94
95static void
96dummy_sa_handler (int signal)
97{
98}
99
100static void
101do_test_signals (void)
102{
103 /* Ensure the initial signal disposition, ignore EINVAL for internal
104 signal such as SIGCANCEL. */
105 for (int sig = 1; sig < _NSIG; ++sig)
106 sigaction (sig: sig, act: &(struct sigaction) { .sa_handler = SIG_DFL,
107 .sa_flags = 0 }, NULL);
108
109 {
110 /* Check if all signals handler are set to SIG_DFL on spawned process. */
111 spawn_signal_test (type: "SIG_DFL", NULL);
112 }
113
114 {
115 /* Same as before, but set SIGUSR1 and SIGUSR2 to a handler different than
116 SIG_IGN or SIG_DFL. */
117 struct sigaction sa = { 0 };
118 sa.sa_handler = dummy_sa_handler;
119 xsigaction (SIGUSR1, newact: &sa, NULL);
120 xsigaction (SIGUSR2, newact: &sa, NULL);
121 spawn_signal_test (type: "SIG_DFL", NULL);
122 }
123
124 {
125 /* Check if SIG_IGN is keep as is. */
126 struct sigaction sa = { 0 };
127 sa.sa_handler = SIG_IGN;
128 xsigaction (SIGUSR1, newact: &sa, NULL);
129 xsigaction (SIGUSR2, newact: &sa, NULL);
130 spawn_signal_test (type: "SIG_IGN", NULL);
131 }
132
133 {
134 /* Check if SIG_IGN handlers are set to SIG_DFL. */
135 posix_spawnattr_t attr;
136 posix_spawnattr_init (attr: &attr);
137 sigset_t mask;
138 sigemptyset (&mask);
139 sigaddset (&mask, SIGUSR1);
140 sigaddset (&mask, SIGUSR2);
141 posix_spawnattr_setsigdefault (attr: &attr, sigdefault: &mask);
142 posix_spawnattr_setflags (attr: &attr, POSIX_SPAWN_SETSIGDEF);
143 spawn_signal_test (type: "SIG_DFL", attr: &attr);
144 posix_spawnattr_destroy (attr: &attr);
145 }
146}
147
148static int
149do_test (int argc, char *argv[])
150{
151 /* We must have either:
152
153 - one or four parameters if called initially:
154 + argv[1]: path for ld.so optional
155 + argv[2]: "--library-path" optional
156 + argv[3]: the library path optional
157 + argv[4]: the application name
158
159 - six parameters left if called through re-execution:
160 + argv[1]: the application name
161 + argv[2]: check SIG_IGN/SIG_DFL.
162
163 * When built with --enable-hardcoded-path-in-tests or issued without
164 using the loader directly. */
165
166 if (restart)
167 handle_restart (argc: argc - 1, argv: &argv[1]);
168
169 TEST_VERIFY_EXIT (argc == 2 || argc == 5);
170
171 int i;
172 for (i = 0; i < argc - 1; i++)
173 spargs[i] = argv[i + 1];
174 spargs[i++] = (char *) "--direct";
175 spargs[i++] = (char *) "--restart";
176 check_type_argc = i++;
177 spargs[i] = NULL;
178
179
180 do_test_signals ();
181
182 return 0;
183}
184
185#define TEST_FUNCTION_ARGV do_test
186#include <support/test-driver.c>
187

source code of glibc/posix/tst-spawn7.c