|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
1 | 2 | /* |
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 |
| 3 | + * Copyright (c) International Business Machines Corp., 2001 |
| 4 | + * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> |
18 | 5 | */ |
19 | 6 |
|
20 | | -/* |
21 | | - * Test Name: vfork02 |
22 | | - * |
23 | | - * Test Description: |
| 7 | +/*\ |
24 | 8 | * Fork a process using vfork() and verify that, the pending signals in |
25 | 9 | * the parent are not pending in the child process. |
26 | | - * $ |
27 | | - * Expected Result: |
28 | | - * The signal which is pending in the parent should not be pending in the |
29 | | - * child process. |
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 | | - * vfork02 [-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 | | - * None. |
66 | | - * |
67 | 10 | */ |
68 | | -#define _GNU_SOURCE 1 |
69 | 11 |
|
70 | | -#include <stdio.h> |
71 | | -#include <sys/types.h> |
72 | | -#include <errno.h> |
73 | | -#include <unistd.h> |
74 | | -#include <fcntl.h> |
75 | | -#include <string.h> |
76 | | -#include <signal.h> |
77 | | -#include <sys/stat.h> |
78 | | -#include <sys/wait.h> |
| 12 | +#include "tst_test.h" |
79 | 13 |
|
80 | | -#include "test.h" |
81 | | -#include "tso_safe_macros.h" |
| 14 | +static sigset_t mask; |
82 | 15 |
|
83 | | -char *TCID = "vfork02"; |
84 | | -int TST_TOTAL = 1; |
| 16 | +static void run(void) |
| 17 | +{ |
| 18 | + if (!vfork()) { |
| 19 | + sigset_t signal; |
85 | 20 |
|
86 | | -void setup(); /* Main setup function of test */ |
87 | | -void cleanup(); /* cleanup function for the test */ |
88 | | -void sig_handler(); /* signal catching function */ |
| 21 | + tst_res(TINFO, "child: verify if SIGUSR1 signal is not on hold"); |
89 | 22 |
|
90 | | -int main(int ac, char **av) |
91 | | -{ |
92 | | - int lc; |
93 | | - pid_t cpid; /* process id of the child process */ |
94 | | - int exit_status; /* exit status of child process */ |
95 | | - sigset_t PendSig; /* variable to hold pending signal */ |
96 | | - |
97 | | - tst_parse_opts(ac, av, NULL, NULL); |
98 | | - |
99 | | - setup(); |
100 | | - |
101 | | - for (lc = 0; TEST_LOOPING(lc); lc++) { |
102 | | - |
103 | | - tst_count = 0; |
104 | | - |
105 | | - /* |
106 | | - * Call vfork(2) to create a child process without |
107 | | - * fully copying the address space of parent. |
108 | | - */ |
109 | | - TEST(vfork()); |
110 | | - |
111 | | - if ((cpid = TEST_RETURN) == -1) { |
112 | | - tst_resm(TFAIL, "vfork() Failed, errno=%d : %s", |
113 | | - TEST_ERRNO, strerror(TEST_ERRNO)); |
114 | | - } else if (cpid == 0) { /* Child process */ |
115 | | - /* |
116 | | - * Check whether the pending signal SIGUSR1 |
117 | | - * in the parent is also pending in the child |
118 | | - * process by storing it in a variable. |
119 | | - */ |
120 | | - if (sigpending(&PendSig) == -1) { |
121 | | - tst_resm(TFAIL, "sigpending function " |
122 | | - "failed in child"); |
123 | | - _exit(1); |
124 | | - } |
125 | | - |
126 | | - /* Check if SIGUSR1 is pending in child */ |
127 | | - if (sigismember(&PendSig, SIGUSR1) != 0) { |
128 | | - tst_resm(TFAIL, "SIGUSR1 also pending " |
129 | | - "in child process"); |
130 | | - _exit(1); |
131 | | - } |
132 | | - |
133 | | - /* |
134 | | - * Exit with normal exit code if everything |
135 | | - * fine |
136 | | - */ |
137 | | - _exit(0); |
138 | | - } else { /* parent process */ |
139 | | - /* |
140 | | - * Let the parent process wait till child completes |
141 | | - * its execution. |
142 | | - */ |
143 | | - wait(&exit_status); |
144 | | - |
145 | | - /* Check for the exit status of child process */ |
146 | | - if (WEXITSTATUS(exit_status) == 0) { |
147 | | - tst_resm(TPASS, "Call to vfork() " |
148 | | - "successful"); |
149 | | - } else if (WEXITSTATUS(exit_status) == 1) { |
150 | | - tst_resm(TFAIL, |
151 | | - "Child process exited abnormally"); |
152 | | - } |
153 | | - } |
154 | | - tst_count++; /* incr. TEST_LOOP counter */ |
155 | | - } |
| 23 | + if (sigpending(&signal) == -1) |
| 24 | + tst_brk(TBROK | TERRNO, "sigpending() error"); |
156 | 25 |
|
157 | | - cleanup(); |
158 | | - tst_exit(); |
| 26 | + TST_EXP_EQ_LI(sigismember(&signal, SIGUSR1), 0); |
159 | 27 |
|
| 28 | + _exit(0); |
| 29 | + } |
160 | 30 | } |
161 | 31 |
|
162 | | -/* |
163 | | - * void |
164 | | - * setup() - performs all ONE TIME setup for this test. |
165 | | - * This function installs signal handler for SIGUSR1, puts signal SIGUSR1 |
166 | | - * on hold and then sends the signal SIGUSR1 to itself so that it is in |
167 | | - * pending state. |
168 | | - */ |
169 | | -void setup(void) |
| 32 | +static void sig_handler(LTP_ATTRIBUTE_UNUSED int signo) |
170 | 33 | { |
171 | | - sigset_t PendSig; /* variable to hold pending signal */ |
| 34 | +} |
172 | 35 |
|
173 | | - tst_sig(FORK, DEF_HANDLER, cleanup); |
| 36 | +static void setup(void) |
| 37 | +{ |
| 38 | + struct sigaction action; |
| 39 | + sigset_t signal; |
174 | 40 |
|
175 | | - TEST_PAUSE; |
| 41 | + tst_res(TINFO, "parent: hold SIGUSR1 signal"); |
176 | 42 |
|
177 | | - /* Install the signal handler */ |
178 | | - if (signal(SIGUSR1, sig_handler) == SIG_ERR) { |
179 | | - tst_brkm(TBROK, cleanup, "Fails to catch the signal SIGUSR1"); |
180 | | - } |
| 43 | + memset(&action, 0, sizeof(action)); |
| 44 | + action.sa_handler = sig_handler; |
| 45 | + SAFE_SIGACTION(SIGUSR1, &action, NULL); |
181 | 46 |
|
182 | | - /* Hold the signal SIGUSR1 */ |
183 | | - if (sighold(SIGUSR1) == -1) { |
184 | | - tst_brkm(TBROK, cleanup, |
185 | | - "sighold failed to hold the signal SIGUSR1"); |
186 | | - } |
| 47 | + SAFE_SIGEMPTYSET(&mask); |
| 48 | + SAFE_SIGADDSET(&mask, SIGUSR1); |
| 49 | + SAFE_SIGPROCMASK(SIG_BLOCK, &mask, NULL); |
187 | 50 |
|
188 | | - /* Send the signal SIGUSR1 to itself so that SIGUSR1 is pending */ |
189 | | - SAFE_KILL(cleanup, getpid(), SIGUSR1); |
| 51 | + SAFE_KILL(getpid(), SIGUSR1); |
190 | 52 |
|
191 | | - /* If SIGUSR1 is not pending in the parent, fail */ |
192 | | - if (sigpending(&PendSig) == -1) { |
193 | | - tst_brkm(TBROK, cleanup, |
194 | | - "sigpending function failed in parent"); |
195 | | - } |
| 53 | + if (sigpending(&signal) == -1) |
| 54 | + tst_brk(TBROK | TERRNO, "sigpending() error"); |
| 55 | + |
| 56 | + TEST(sigismember(&signal, SIGUSR1)); |
| 57 | + if (TST_RET != 1) { |
| 58 | + if (TST_RET == -1) |
| 59 | + tst_brk(TBROK | TERRNO, "sigismember() error"); |
196 | 60 |
|
197 | | - /* Check if SIGUSR1 is pending in parent */ |
198 | | - if (sigismember(&PendSig, SIGUSR1) != 1) { |
199 | | - tst_brkm(TBROK, cleanup, |
200 | | - "SIGUSR1 signal is not pending in parent"); |
| 61 | + tst_brk(TBROK, "SIGUSR1 is not on hold"); |
201 | 62 | } |
202 | 63 | } |
203 | 64 |
|
204 | | -/* |
205 | | - * void |
206 | | - * sig_handler() - signal catching function for 'SIGUSR1' signal. |
207 | | - * $ |
208 | | - * This is a null function and used only to catch the above signal |
209 | | - * generated in parent process. |
210 | | - */ |
211 | | -void sig_handler(void) |
| 65 | +static void cleanup(void) |
212 | 66 | { |
| 67 | + SAFE_SIGEMPTYSET(&mask); |
| 68 | + SAFE_SIGADDSET(&mask, SIGUSR1); |
| 69 | + SAFE_SIGPROCMASK(SIG_UNBLOCK, &mask, NULL); |
213 | 70 | } |
214 | 71 |
|
215 | | -/* |
216 | | - * void |
217 | | - * cleanup() - performs all ONE TIME cleanup for this test at |
218 | | - * completion or premature exit. |
219 | | - * Release the signal 'SIGUSR1' if still in pending state. |
220 | | - */ |
221 | | -void cleanup(void) |
222 | | -{ |
223 | | - |
224 | | - /* Release the signal 'SIGUSR1' if in pending state */ |
225 | | - if (sigrelse(SIGUSR1) == -1) { |
226 | | - tst_brkm(TBROK, NULL, "Failed to release 'SIGUSR1' in cleanup"); |
227 | | - } |
228 | | - |
229 | | -} |
| 72 | +static struct tst_test test = { |
| 73 | + .test_all = run, |
| 74 | + .setup = setup, |
| 75 | + .cleanup = cleanup, |
| 76 | + .forks_child = 1, |
| 77 | +}; |
0 commit comments