* [LTP] [PATCH v3 1/3] syscalls: refactor fork09 using new API
2026-03-09 10:45 [LTP] [PATCH v3 0/3] Refactor tests which are verifying fork/vfork functionalities Andrea Cervesato
@ 2026-03-09 10:45 ` Andrea Cervesato
2026-03-10 11:50 ` Cyril Hrubis
2026-03-09 10:45 ` [LTP] [PATCH v3 2/3] syscalls: refactor vfork01 " Andrea Cervesato
` (2 subsequent siblings)
3 siblings, 1 reply; 6+ messages in thread
From: Andrea Cervesato @ 2026-03-09 10:45 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Reviewed-by: Petr Vorel <pvorel@suse.cz>
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
testcases/kernel/syscalls/fork/fork09.c | 221 +++++++++++---------------------
1 file changed, 74 insertions(+), 147 deletions(-)
diff --git a/testcases/kernel/syscalls/fork/fork09.c b/testcases/kernel/syscalls/fork/fork09.c
index c3b9cf45bf947604fed3217dbdda9b3c1657add9..d5c5e116dfcf61065a23de3207740da0e22c66ba 100644
--- a/testcases/kernel/syscalls/fork/fork09.c
+++ b/testcases/kernel/syscalls/fork/fork09.c
@@ -1,172 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (c) International Business Machines Corp., 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * NAME
- * fork09.c
- *
- * DESCRIPTION
- * Check that child has access to a full set of files.
- *
- * ALGORITHM
- * Parent opens a maximum number of files
- * Child closes one and attempts to open another, it should be
- * available
- *
- * USAGE
- * fork09
- *
- * HISTORY
+ * Copyright (c) International Business Machines Corp., 2001
* 07/2001 Ported by Wayne Boyer
- *
* 10/2008 Suzuki K P <suzuki@in.ibm.com>
- * Fix maximum number of files open logic.
*
- * RESTRICTIONS
- * None
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
*/
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h> /* for _SC_OPEN_MAX */
-#include "test.h"
-#include "tso_safe_macros.h"
-
-char *TCID = "fork09";
-int TST_TOTAL = 1;
+/*\
+ * Verify that a forked child can close all the files which have been open by
+ * the parent process, after opening and closing one of them.
+ */
-static void setup(void);
-static void cleanup(void);
+#include "tst_test.h"
+#include "tst_safe_stdio.h"
-static char filname[40], childfile[40];
-static int first;
-static FILE **fildeses; /* file streams */
-static int mypid, nfiles;
+#define FILE_PREFIX "ltp_file"
-#define OPEN_MAX (sysconf(_SC_OPEN_MAX))
+static FILE **open_files;
+static long file_open_max;
-int main(int ac, char **av)
+static void run(void)
{
- int pid, status, nf;
-
- int lc;
-
- tst_parse_opts(ac, av, NULL, NULL);
-
- setup();
-
- fildeses = malloc((OPEN_MAX + 10) * sizeof(FILE *));
- if (fildeses == NULL)
- tst_brkm(TBROK, cleanup, "malloc failed");
-
- for (lc = 0; TEST_LOOPING(lc); lc++) {
- tst_count = 0;
- mypid = getpid();
-
- tst_resm(TINFO, "OPEN_MAX is %ld", OPEN_MAX);
-
- /* establish first free file */
- sprintf(filname, "fork09.%d", mypid);
- first = SAFE_CREAT(cleanup, filname, 0660);
- close(first);
-
- tst_resm(TINFO, "first file descriptor is %d ", first);
-
- SAFE_UNLINK(cleanup, filname);
-
- /*
- * now open all the files for the test
- */
- for (nfiles = first; nfiles < OPEN_MAX; nfiles++) {
- sprintf(filname, "file%d.%d", nfiles, mypid);
- fildeses[nfiles] = fopen(filname, "a");
- if (fildeses[nfiles] == NULL) {
- /* Did we already reach OPEN_MAX ? */
- if (errno == EMFILE)
- break;
- tst_brkm(TBROK, cleanup, "Parent: cannot open "
- "file %d %s errno = %d", nfiles,
- filname, errno);
- }
-#ifdef DEBUG
- tst_resm(TINFO, "filname: %s", filname);
-#endif
- }
+ FILE *f;
+ long nfiles;
+ long totfiles;
+ int name_len;
+ char name[PATH_MAX];
+ char reopen[PATH_MAX];
- tst_resm(TINFO, "Parent reporting %d files open", nfiles - 1);
-
- pid = fork();
- if (pid == -1)
- tst_brkm(TBROK, cleanup, "Fork failed");
-
- if (pid == 0) { /* child */
- nfiles--;
- if (fclose(fildeses[nfiles]) == -1) {
- tst_resm(TINFO, "Child could not close file "
- "#%d, errno = %d", nfiles, errno);
- exit(1);
- } else {
- sprintf(childfile, "cfile.%d", getpid());
- fildeses[nfiles] = fopen(childfile, "a");
- if (fildeses[nfiles] == NULL) {
- tst_resm(TINFO, "Child could not open "
- "file %s, errno = %d",
- childfile, errno);
- exit(1);
- } else {
- tst_resm(TINFO, "Child opened new "
- "file #%d", nfiles);
- unlink(childfile);
- exit(0);
- }
- }
- } else { /* parent */
- wait(&status);
- if (status >> 8 != 0)
- tst_resm(TFAIL, "test 1 FAILED");
- else
- tst_resm(TPASS, "test 1 PASSED");
- }
+ memset(reopen, 0, PATH_MAX);
+
+ tst_res(TINFO, "Opening files from parent");
+
+ for (nfiles = 0; nfiles < file_open_max; nfiles++) {
+ name_len = snprintf(name, PATH_MAX, "%s%lu", FILE_PREFIX, nfiles);
+ if (!nfiles)
+ memcpy(reopen, name, name_len);
- /* clean up things in case we are looping */
- for (nf = first; nf < nfiles; nf++) {
- fclose(fildeses[nf]);
- sprintf(filname, "file%d.%d", nf, mypid);
- unlink(filname);
+ f = fopen(name, "a");
+ if (!f) {
+ /* raised if we reached OPEN_MAX */
+ if (errno == EMFILE)
+ break;
+
+ tst_brk(TBROK | TERRNO, "fopen() error");
}
+
+ open_files[nfiles] = f;
}
- cleanup();
- tst_exit();
+ totfiles = nfiles;
+
+ if (!totfiles)
+ tst_brk(TBROK, "Parent couldn't open any file");
+
+ tst_res(TINFO, "Closing %lu files from child", totfiles);
+
+ if (!SAFE_FORK()) {
+ SAFE_FCLOSE(open_files[0]);
+ open_files[0] = SAFE_FOPEN(reopen, "a");
+
+ for (nfiles = nfiles - 1; nfiles >= 0; nfiles--)
+ SAFE_FCLOSE(open_files[nfiles]);
+
+ _exit(0);
+ }
+
+ tst_reap_children();
+
+ tst_res(TPASS, "Child closed all parent's files");
+
+ for (nfiles = 0; nfiles < totfiles; nfiles++) {
+ snprintf(name, PATH_MAX, "%s%lu", FILE_PREFIX, nfiles);
+
+ SAFE_FCLOSE(open_files[nfiles]);
+ SAFE_UNLINK(name);
+ }
}
static void setup(void)
{
- tst_sig(FORK, DEF_HANDLER, cleanup);
- umask(0);
-
- TEST_PAUSE;
- tst_tmpdir();
+ file_open_max = sysconf(_SC_OPEN_MAX);
+ open_files = SAFE_MALLOC(sizeof(FILE *) * file_open_max);
}
static void cleanup(void)
{
- tst_rmdir();
+ free(open_files);
}
+
+static struct tst_test test = {
+ .test_all = run,
+ .setup = setup,
+ .cleanup = cleanup,
+ .forks_child = 1,
+ .needs_tmpdir = 1,
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 6+ messages in thread* [LTP] [PATCH v3 2/3] syscalls: refactor vfork01 using new API
2026-03-09 10:45 [LTP] [PATCH v3 0/3] Refactor tests which are verifying fork/vfork functionalities Andrea Cervesato
2026-03-09 10:45 ` [LTP] [PATCH v3 1/3] syscalls: refactor fork09 using new API Andrea Cervesato
@ 2026-03-09 10:45 ` Andrea Cervesato
2026-03-09 10:45 ` [LTP] [PATCH v3 3/3] syscalls: refactor vfork02 " Andrea Cervesato
2026-03-10 13:20 ` [LTP] [PATCH v3 0/3] Refactor tests which are verifying fork/vfork functionalities Andrea Cervesato via ltp
3 siblings, 0 replies; 6+ messages in thread
From: Andrea Cervesato @ 2026-03-09 10:45 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
testcases/kernel/syscalls/vfork/vfork01.c | 374 ++++--------------------------
1 file changed, 48 insertions(+), 326 deletions(-)
diff --git a/testcases/kernel/syscalls/vfork/vfork01.c b/testcases/kernel/syscalls/vfork/vfork01.c
index b050776b7982e568f59b31547a6ebf72a1dba880..81408fc44fa7a0fc8dbd76c3ab526c63aa19798c 100644
--- a/testcases/kernel/syscalls/vfork/vfork01.c
+++ b/testcases/kernel/syscalls/vfork/vfork01.c
@@ -1,352 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
- *
- * Copyright (c) International Business Machines Corp., 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Copyright (c) International Business Machines Corp., 2001
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
*/
-/*
- * Name: vfork01
- *
- * Test Description:
- * Fork a process using vfork() and verify that, the attribute values like
- * euid, ruid, suid, egid, rgid, sgid, umask, inode and device number of
- * root and current working directories are same as that of the parent
- * process.
- * $
- * Expected Result:
- * The attribute values like euid, ruid, suid, egid, rgid, sgid, umask, inode
- * and device number of root and current working directory of the parent and
- * child processes should be equal.
- *
- * Algorithm:
- * Setup:
- * Setup signal handling.
- * Pause for SIGUSR1 if option specified.
- *
- * Test:
- * Loop if the proper options are given.
- * Execute system call
- * Check return code, if system call failed (return=-1)
- * Log the errno and Issue a FAIL message.
- * Otherwise,
- * Verify the Functionality of system call
- * if successful,
- * Issue Functionality-Pass message.
- * Otherwise,
- * Issue Functionality-Fail message.
- * Cleanup:
- * Print errno log and/or timing stats if options given
- *
- * Usage: <for command-line>
- * vfork01 [-c n] [-e] [-f] [-i n] [-I x] [-p x] [-t]
- * where, -c n : Run n copies concurrently.
- * -e : Turn on errno logging.
- * -f : Turn off functionality Testing.
- * -i n : Execute test n times.
- * -I x : Execute test for x seconds.
- * -P x : Pause for x seconds between iterations.
- * -t : Turn on syscall timing.
- *
- * History
- * 07/2001 John George
- * -Ported
- *
- * Restrictions:
- * None.
- *
+/*\
+ * Fork a process using `vfork()` and verify that the attribute values like
+ * euid, ruid, suid, egid, rgid, sgid, umask, inode and device number of
+ * root and current working directories are the same of the parent
+ * process ones.
*/
-#define _GNU_SOURCE 1
-#include <stdio.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <signal.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include "test.h"
-
-char *TCID = "vfork01";
-int TST_TOTAL = 1;
-
-/* Variables to hold parent/child eff/real/saved uid/gid values */
-uid_t Peuid, Ceuid, Csuid, Psuid, Pruid, Cruid;
-gid_t Pegid, Cegid, Psgid, Csgid, Prgid, Crgid;
-mode_t Pumask, Cumask;
+#include "tst_test.h"
+#include "tst_uid.h"
-char *Pcwd, *Ccwd; /*
- * pathname of working directory of
- * child/parent process.
- */
-/* stat structure to hold directory/inode information for parent/child */
-struct stat StatPbuf;
-struct stat StatCbuf;
-struct stat Stat_cwd_Pbuf;
-struct stat Stat_cwd_Cbuf;
-
-void setup(); /* Main setup function of test */
-void cleanup(); /* cleanup function for the test */
-
-int main(int ac, char **av)
+static void run(void)
{
- int lc;
- pid_t cpid; /* process id of the child process */
- int exit_status; /* exit status of child process */
-
- tst_parse_opts(ac, av, NULL, NULL);
-
- setup();
-
- for (lc = 0; TEST_LOOPING(lc); lc++) {
-
- tst_count = 0;
-
- /*
- * Call vfork(2) to create a child process without
- * fully copying the address space of parent.
- */
- TEST(vfork());
-
- if ((cpid = TEST_RETURN) == -1) {
- tst_resm(TFAIL, "vfork() Failed, errno=%d : %s",
- TEST_ERRNO, strerror(TEST_ERRNO));
- } else if (cpid == 0) { /* Child process */
- /*
- * Get the euid, ruid, egid, rgid, umask value
- * and the current working directory of the
- * child process
- */
- if (getresuid(&Cruid, &Ceuid, &Csuid) < 0) {
- tst_resm(TFAIL, "getresuid() fails to "
- "get real/eff./saved uid of "
- "child process");
- _exit(1);
- }
-
- if (getresgid(&Crgid, &Cegid, &Csgid) < 0) {
- tst_resm(TFAIL, "getresgid() fails to "
- "get real/eff./saved gid of "
- "child process");
- _exit(1);
- }
-
- /*
- * Get the file mode creation mask value of
- * child process by setting value zero and
- * restore the previous mask value.
- */
- Cumask = umask(0);
-
- /*
- * Restore the process mask of child to
- * previous value.
- */
- umask(Cumask);
-
- /*
- * Get the pathname of current working
- * directory for the child process.
- */
- if ((Ccwd = (char *)getcwd(NULL,
- BUFSIZ)) == NULL) {
- tst_resm(TFAIL, "getcwd failed for the "
- "child process");
- _exit(1);
- }
+ char *p_cwd, *c_cwd;
+ mode_t p_mask, c_mask;
+ static uid_t p_ruid, p_euid, p_suid;
+ static gid_t p_rgid, p_egid, p_sgid;
+ struct stat p_cwd_stat, c_cwd_stat;
+ struct stat p_root_stat, c_root_stat;
- /*
- * Get the device number and the inode
- * number of "/" directory for the child
- * process.
- */
- if (stat("/", &StatCbuf) < 0) {
- tst_resm(TFAIL, "stat(2) failed to get "
- "info. of'/' in the child "
- "process");
- _exit(1);
- }
+ p_mask = umask(0);
+ umask(p_mask);
- /*
- * Get the device/inode number of "."
- * (working directory) for the child process.
- */
- if (stat(Ccwd, &Stat_cwd_Cbuf) < 0) {
- tst_resm(TFAIL, "stat(2) failed to get "
- "info. of working irectory in "
- "the child");
- _exit(1);
- }
+ p_cwd = getcwd(NULL, BUFSIZ);
- /* Now, do the actual comparision */
- if (Peuid != Ceuid || Pegid != Cegid ||
- Psuid != Csuid || Psgid != Csgid ||
- Pruid != Cruid || Prgid != Crgid ||
- Pumask != Cumask) {
- tst_resm(TFAIL, "Attribute values of "
- "parent and child don't match");
- _exit(1);
- } else {
- tst_resm(TINFO, "Attribute values of "
- "parent and child match");
- }
+ SAFE_GETRESUID(&p_ruid, &p_euid, &p_suid);
+ SAFE_GETRESGID(&p_rgid, &p_egid, &p_sgid);
- /* Check for the same working directories */
- if (strcmp(Pcwd, Ccwd) != 0) {
- tst_resm(TFAIL, "Working directories "
- "of parent and child don't "
- "match");
- _exit(1);
- } else {
- tst_resm(TINFO, "Working directories "
- "of parent and child match");
- }
+ SAFE_STAT(p_cwd, &p_cwd_stat);
+ SAFE_STAT("/", &p_root_stat);
- /*
- * Check for the same device/inode number of
- * '/' directory.
- */
- if ((StatPbuf.st_ino != StatCbuf.st_ino) ||
- (StatPbuf.st_dev != StatCbuf.st_dev)) {
- tst_resm(TFAIL, "Device/inode number "
- "of parent and childs '/' "
- " don't match");
- _exit(1);
- } else {
- tst_resm(TINFO, "Device/inode number "
- "of parent and childs '/' "
- "match");
- }
+ if (!vfork()) {
+ c_mask = umask(0);
+ umask(c_mask);
- /*
- * Check for the same device and inode number
- * of "." (current working directory.
- */
- if ((Stat_cwd_Pbuf.st_ino !=
- Stat_cwd_Cbuf.st_ino) ||
- (Stat_cwd_Pbuf.st_dev !=
- Stat_cwd_Cbuf.st_dev)) {
- tst_resm(TFAIL, "Device/inode number "
- "of parent and childs '.' "
- "don't match");
- _exit(1);
- } else {
- tst_resm(TINFO, "Device/inode number "
- "of parent and childs '.' "
- "don't match");
- }
+ TST_EXP_EQ_LI(p_mask, c_mask);
- /*
- * Exit with normal exit code if everything
- * fine
- */
- _exit(0);
+ c_cwd = getcwd(NULL, BUFSIZ);
+ SAFE_STAT(c_cwd, &c_cwd_stat);
- } else { /* parent process */
- /*
- * Let the parent process wait till child completes
- * its execution.
- */
- wait(&exit_status);
+ TST_EXP_EQ_STR(p_cwd, c_cwd);
+ free(c_cwd);
- /* Check for the exit status of child process */
- if (WEXITSTATUS(exit_status) == 0) {
- tst_resm(TPASS, "Call of vfork() successful");
- } else if (WEXITSTATUS(exit_status) == 1) {
- tst_resm(TFAIL,
- "Child process exited abnormally");
- }
- }
- tst_count++; /* incr. TEST_LOOP counter */
- }
-
- cleanup();
- tst_exit();
-}
-
-/*
- * void
- * setup() - performs all ONE TIME setup for this test.
- * This function gets real/effective/saved uid/gid, umask, the device/inode
- * number of '/' and current working directory for the parent process.
- */
-void setup(void)
-{
+ TST_EXP_EQ_LI(p_cwd_stat.st_ino, c_cwd_stat.st_ino);
+ TST_EXP_EQ_LI(p_cwd_stat.st_dev, c_cwd_stat.st_dev);
- tst_sig(FORK, DEF_HANDLER, cleanup);
+ SAFE_STAT("/", &c_root_stat);
- TEST_PAUSE;
+ TST_EXP_EQ_LI(p_root_stat.st_ino, c_root_stat.st_ino);
+ TST_EXP_EQ_LI(p_root_stat.st_dev, c_root_stat.st_dev);
- /*
- * Get the euid, ruid, egid, rgid, umask value
- * and the current working directory of the parent process.
- */
- if (getresuid(&Pruid, &Peuid, &Psuid) < 0) {
- tst_brkm(TFAIL, cleanup, "getresuid() fails to get "
- "real/eff./saved uid of parent");
- }
+ if (tst_check_resuid("resuid()", p_ruid, p_euid, p_suid))
+ tst_res(TPASS, "Parent and child UID are matching");
- if (getresgid(&Prgid, &Pegid, &Psgid) < 0) {
- tst_brkm(TFAIL, cleanup, "getresgid() fails to get "
- "real/eff./saved gid of parent");
- }
+ if (tst_check_resgid("resgid()", p_rgid, p_egid, p_sgid))
+ tst_res(TPASS, "Parent and child GID are matching");
- /* Get the process file mode creation mask by setting value 0 */
- Pumask = umask(0);
- umask(Pumask); /*
- * Restore the mask value of the
- * process.
- */
- /*
- * Get the pathname of current working directory of the parent
- * process.
- */
- if ((Pcwd = (char *)getcwd(NULL, BUFSIZ)) == NULL) {
- tst_brkm(TFAIL, cleanup,
- "getcwd failed for the parent process");
+ _exit(0);
}
- /*
- * Get the device and inode number of root directory for the
- * parent process.
- */
- if (stat("/", &StatPbuf) == -1) {
- tst_brkm(TFAIL, cleanup, "stat(2) failed to get info. of '/' "
- "in parent process");
- }
+ tst_reap_children();
- /*
- * Get the device number and the inode number of "." (current-
- * working directory) for the parent process.
- */
- if (stat(Pcwd, &Stat_cwd_Pbuf) < 0) {
- tst_brkm(TFAIL, cleanup, "stat(2) failed to get info. of "
- "working directory in parent process");
- }
+ free(p_cwd);
}
-/*
- * void
- * cleanup() - performs all ONE TIME cleanup for this test at
- * completion or premature exit.
- */
-void cleanup(void)
-{
-
-}
+static struct tst_test test = {
+ .test_all = run,
+ .forks_child = 1,
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 6+ messages in thread* [LTP] [PATCH v3 3/3] syscalls: refactor vfork02 using new API
2026-03-09 10:45 [LTP] [PATCH v3 0/3] Refactor tests which are verifying fork/vfork functionalities Andrea Cervesato
2026-03-09 10:45 ` [LTP] [PATCH v3 1/3] syscalls: refactor fork09 using new API Andrea Cervesato
2026-03-09 10:45 ` [LTP] [PATCH v3 2/3] syscalls: refactor vfork01 " Andrea Cervesato
@ 2026-03-09 10:45 ` Andrea Cervesato
2026-03-10 13:20 ` [LTP] [PATCH v3 0/3] Refactor tests which are verifying fork/vfork functionalities Andrea Cervesato via ltp
3 siblings, 0 replies; 6+ messages in thread
From: Andrea Cervesato @ 2026-03-09 10:45 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Replace the deprecated sigrelse/sighold usage and replace them with
sigprocmask/sigaction.
Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
testcases/kernel/syscalls/vfork/vfork02.c | 248 ++++++------------------------
1 file changed, 48 insertions(+), 200 deletions(-)
diff --git a/testcases/kernel/syscalls/vfork/vfork02.c b/testcases/kernel/syscalls/vfork/vfork02.c
index f630c9572b609d2af18e8852c1e5a0dcb16172ff..26d5f1bb9c897afe1121cfe3ed4d5a70456d17b8 100644
--- a/testcases/kernel/syscalls/vfork/vfork02.c
+++ b/testcases/kernel/syscalls/vfork/vfork02.c
@@ -1,229 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
- *
- * Copyright (c) International Business Machines Corp., 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Copyright (c) International Business Machines Corp., 2001
+ * Copyright (C) 2026 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
*/
-/*
- * Test Name: vfork02
- *
- * Test Description:
+/*\
* Fork a process using vfork() and verify that, the pending signals in
* the parent are not pending in the child process.
- * $
- * Expected Result:
- * The signal which is pending in the parent should not be pending in the
- * child process.
- *
- * Algorithm:
- * Setup:
- * Setup signal handling.
- * Pause for SIGUSR1 if option specified.
- *
- * Test:
- * Loop if the proper options are given.
- * Execute system call
- * Check return code, if system call failed (return=-1)
- * Log the errno and Issue a FAIL message.
- * Otherwise,
- * Verify the Functionality of system call
- * if successful,
- * Issue Functionality-Pass message.
- * Otherwise,
- * Issue Functionality-Fail message.
- * Cleanup:
- * Print errno log and/or timing stats if options given
- *
- * Usage: <for command-line>
- * vfork02 [-c n] [-e] [-f] [-i n] [-I x] [-p x] [-t]
- * where, -c n : Run n copies concurrently.
- * -e : Turn on errno logging.
- * -f : Turn off functionality Testing.
- * -i n : Execute test n times.
- * -I x : Execute test for x seconds.
- * -P x : Pause for x seconds between iterations.
- * -t : Turn on syscall timing.
- *
- * History
- * 07/2001 John George
- * -Ported
- *
- * Restrictions:
- * None.
- *
*/
-#define _GNU_SOURCE 1
-#include <stdio.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
+#include "tst_test.h"
-#include "test.h"
-#include "tso_safe_macros.h"
+static sigset_t mask;
-char *TCID = "vfork02";
-int TST_TOTAL = 1;
+static void run(void)
+{
+ if (!vfork()) {
+ sigset_t signal;
-void setup(); /* Main setup function of test */
-void cleanup(); /* cleanup function for the test */
-void sig_handler(); /* signal catching function */
+ tst_res(TINFO, "child: verify if SIGUSR1 signal is not on hold");
-int main(int ac, char **av)
-{
- int lc;
- pid_t cpid; /* process id of the child process */
- int exit_status; /* exit status of child process */
- sigset_t PendSig; /* variable to hold pending signal */
-
- tst_parse_opts(ac, av, NULL, NULL);
-
- setup();
-
- for (lc = 0; TEST_LOOPING(lc); lc++) {
-
- tst_count = 0;
-
- /*
- * Call vfork(2) to create a child process without
- * fully copying the address space of parent.
- */
- TEST(vfork());
-
- if ((cpid = TEST_RETURN) == -1) {
- tst_resm(TFAIL, "vfork() Failed, errno=%d : %s",
- TEST_ERRNO, strerror(TEST_ERRNO));
- } else if (cpid == 0) { /* Child process */
- /*
- * Check whether the pending signal SIGUSR1
- * in the parent is also pending in the child
- * process by storing it in a variable.
- */
- if (sigpending(&PendSig) == -1) {
- tst_resm(TFAIL, "sigpending function "
- "failed in child");
- _exit(1);
- }
-
- /* Check if SIGUSR1 is pending in child */
- if (sigismember(&PendSig, SIGUSR1) != 0) {
- tst_resm(TFAIL, "SIGUSR1 also pending "
- "in child process");
- _exit(1);
- }
-
- /*
- * Exit with normal exit code if everything
- * fine
- */
- _exit(0);
- } else { /* parent process */
- /*
- * Let the parent process wait till child completes
- * its execution.
- */
- wait(&exit_status);
-
- /* Check for the exit status of child process */
- if (WEXITSTATUS(exit_status) == 0) {
- tst_resm(TPASS, "Call to vfork() "
- "successful");
- } else if (WEXITSTATUS(exit_status) == 1) {
- tst_resm(TFAIL,
- "Child process exited abnormally");
- }
- }
- tst_count++; /* incr. TEST_LOOP counter */
- }
+ if (sigpending(&signal) == -1)
+ tst_brk(TBROK | TERRNO, "sigpending() error");
- cleanup();
- tst_exit();
+ TST_EXP_EQ_LI(sigismember(&signal, SIGUSR1), 0);
+ _exit(0);
+ }
}
-/*
- * void
- * setup() - performs all ONE TIME setup for this test.
- * This function installs signal handler for SIGUSR1, puts signal SIGUSR1
- * on hold and then sends the signal SIGUSR1 to itself so that it is in
- * pending state.
- */
-void setup(void)
+static void sig_handler(LTP_ATTRIBUTE_UNUSED int signo)
{
- sigset_t PendSig; /* variable to hold pending signal */
+}
- tst_sig(FORK, DEF_HANDLER, cleanup);
+static void setup(void)
+{
+ struct sigaction action;
+ sigset_t signal;
- TEST_PAUSE;
+ tst_res(TINFO, "parent: hold SIGUSR1 signal");
- /* Install the signal handler */
- if (signal(SIGUSR1, sig_handler) == SIG_ERR) {
- tst_brkm(TBROK, cleanup, "Fails to catch the signal SIGUSR1");
- }
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = sig_handler;
+ SAFE_SIGACTION(SIGUSR1, &action, NULL);
- /* Hold the signal SIGUSR1 */
- if (sighold(SIGUSR1) == -1) {
- tst_brkm(TBROK, cleanup,
- "sighold failed to hold the signal SIGUSR1");
- }
+ SAFE_SIGEMPTYSET(&mask);
+ SAFE_SIGADDSET(&mask, SIGUSR1);
+ SAFE_SIGPROCMASK(SIG_BLOCK, &mask, NULL);
- /* Send the signal SIGUSR1 to itself so that SIGUSR1 is pending */
- SAFE_KILL(cleanup, getpid(), SIGUSR1);
+ SAFE_KILL(getpid(), SIGUSR1);
- /* If SIGUSR1 is not pending in the parent, fail */
- if (sigpending(&PendSig) == -1) {
- tst_brkm(TBROK, cleanup,
- "sigpending function failed in parent");
- }
+ if (sigpending(&signal) == -1)
+ tst_brk(TBROK | TERRNO, "sigpending() error");
+
+ TEST(sigismember(&signal, SIGUSR1));
+ if (TST_RET != 1) {
+ if (TST_RET == -1)
+ tst_brk(TBROK | TERRNO, "sigismember() error");
- /* Check if SIGUSR1 is pending in parent */
- if (sigismember(&PendSig, SIGUSR1) != 1) {
- tst_brkm(TBROK, cleanup,
- "SIGUSR1 signal is not pending in parent");
+ tst_brk(TBROK, "SIGUSR1 is not on hold");
}
}
-/*
- * void
- * sig_handler() - signal catching function for 'SIGUSR1' signal.
- * $
- * This is a null function and used only to catch the above signal
- * generated in parent process.
- */
-void sig_handler(void)
+static void cleanup(void)
{
+ SAFE_SIGEMPTYSET(&mask);
+ SAFE_SIGADDSET(&mask, SIGUSR1);
+ SAFE_SIGPROCMASK(SIG_UNBLOCK, &mask, NULL);
}
-/*
- * void
- * cleanup() - performs all ONE TIME cleanup for this test at
- * completion or premature exit.
- * Release the signal 'SIGUSR1' if still in pending state.
- */
-void cleanup(void)
-{
-
- /* Release the signal 'SIGUSR1' if in pending state */
- if (sigrelse(SIGUSR1) == -1) {
- tst_brkm(TBROK, NULL, "Failed to release 'SIGUSR1' in cleanup");
- }
-
-}
+static struct tst_test test = {
+ .test_all = run,
+ .setup = setup,
+ .cleanup = cleanup,
+ .forks_child = 1,
+};
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [LTP] [PATCH v3 0/3] Refactor tests which are verifying fork/vfork functionalities
2026-03-09 10:45 [LTP] [PATCH v3 0/3] Refactor tests which are verifying fork/vfork functionalities Andrea Cervesato
` (2 preceding siblings ...)
2026-03-09 10:45 ` [LTP] [PATCH v3 3/3] syscalls: refactor vfork02 " Andrea Cervesato
@ 2026-03-10 13:20 ` Andrea Cervesato via ltp
3 siblings, 0 replies; 6+ messages in thread
From: Andrea Cervesato via ltp @ 2026-03-10 13:20 UTC (permalink / raw)
To: Andrea Cervesato, Linux Test Project
Merged, thanks for the review!
--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato@suse.com
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 6+ messages in thread