[LTP] [PATCH 1/3] syscalls: refactor fork09 using new API

Andrea Cervesato andrea.cervesato@suse.de
Tue Jan 27 13:50:09 CET 2026


From: Andrea Cervesato <andrea.cervesato@suse.com>

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 testcases/kernel/syscalls/fork/fork09.c | 218 ++++++++++----------------------
 1 file changed, 69 insertions(+), 149 deletions(-)

diff --git a/testcases/kernel/syscalls/fork/fork09.c b/testcases/kernel/syscalls/fork/fork09.c
index 32bad89b35575f1597bed1a44ef3b984bd1db3bd..7ce64b9a1188fe81e1d44d8ea5cb33a2504b8cfd 100644
--- a/testcases/kernel/syscalls/fork/fork09.c
+++ b/testcases/kernel/syscalls/fork/fork09.c
@@ -1,172 +1,92 @@
+// 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
- *	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 "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.
+ */
 
-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;
+	char name[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");
-		}
+	tst_res(TINFO, "Opening files from parent");
+
+	for (nfiles = 0; nfiles < file_open_max; nfiles++) {
+		memset(name, 0, PATH_MAX);
+		snprintf(name, PATH_MAX, "%s%lu", FILE_PREFIX, nfiles);
 
-		/* 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) {
+			if (errno == EMFILE)
+				break;
+
+			tst_brk(TBROK | TERRNO, "fopen() error");
 		}
+
+		open_files[nfiles] = f;
+	}
+
+	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()) {
+		for (nfiles = nfiles - 1; nfiles >= 0; nfiles--)
+			SAFE_FCLOSE(open_files[nfiles]);
+
+		exit(0);
 	}
 
-	cleanup();
-	tst_exit();
+	tst_reap_children();
+
+	tst_res(TPASS, "Child closed all parent's files");
+
+	for (nfiles = 0; nfiles < totfiles; nfiles++) {
+		memset(name, 0, PATH_MAX);
+		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);
+	file_open_max = sysconf(_SC_OPEN_MAX);
 
-	TEST_PAUSE;
-	tst_tmpdir();
+	open_files = SAFE_MMAP(NULL, sizeof(FILE *) * file_open_max,
+			PROT_READ | PROT_WRITE,
+			MAP_ANONYMOUS | MAP_SHARED,
+			-1, 0);
 }
 
 static void cleanup(void)
 {
-	tst_rmdir();
+	if (open_files)
+		SAFE_MUNMAP(open_files, sizeof(FILE *) * file_open_max);
 }
+
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.cleanup = cleanup,
+	.forks_child = 1,
+	.needs_tmpdir = 1,
+};

-- 
2.51.0



More information about the ltp mailing list