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

Cyril Hrubis chrubis@suse.cz
Mon Feb 16 13:42:56 CET 2026


Hi!
> +// SPDX-License-Identifier: GPL-2.0-or-later
>  /*
> - *   Copyright (c) International Business Machines  Corp., 2001

Unless it's a rewritten from scratch this copyright should stay.

> - *   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);

Do we need to put this into a shared memory? We do not modify that in
the child process so there is no reason for changes to be propagated to
the parent...


-- 
Cyril Hrubis
chrubis@suse.cz


More information about the ltp mailing list