[LTP] [PATCH v1] Rewrite fork04 test

Andrea Cervesato andrea.cervesato@suse.de
Wed Sep 6 15:44:52 CEST 2023


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

The old test was outdated, so it has been rewritten from scratch
keeping the idea behind it. Now the test verifies that parent process
shares environment variables with a child process and that child process
doesn't change parent process environment variables.

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 testcases/kernel/syscalls/fork/fork04.c | 361 +++++-------------------
 1 file changed, 63 insertions(+), 298 deletions(-)

diff --git a/testcases/kernel/syscalls/fork/fork04.c b/testcases/kernel/syscalls/fork/fork04.c
index 5e5e42c4e..307845c92 100644
--- a/testcases/kernel/syscalls/fork/fork04.c
+++ b/testcases/kernel/syscalls/fork/fork04.c
@@ -1,328 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
- *
- *
- *    OS Test - Silicon Graphics, Inc.
- *    TEST IDENTIFIER	: fork04
- *    TEST TITLE	: Child inheritance of Environment Variables after fork()
- *    PARENT DOCUMENT	: frktds01
- *    TEST CASE TOTAL	: 3
- *    WALL CLOCK TIME	: 1
- *    CPU TYPES		: ALL
- *    AUTHOR		: Kathy Olmsted
- *    CO-PILOT		: Steve Shaw
- *    DATE STARTED	: 06/17/92
- *    INITIAL RELEASE	: UNICOS 7.0
- *
- *    TEST CASES
- *       Test these environment variables correctly inherited by child:
- *       1. TERM
- *       2. NoTSetzWq
- *       3. TESTPROG
- *
- *    INPUT SPECIFICATIONS
- * 	The standard options for system call tests are accepted.
- *	(See the parse_opts(3) man page).
- *
- *    DURATION
- * 	Terminates - with frequency and infinite modes.
- *
- *    SIGNALS
- * 	Uses SIGUSR1 to pause before test if option set.
- * 	(See the parse_opts(3) man page).
- *
- *    ENVIRONMENTAL NEEDS
- *      No run-time environmental needs.
- *
- *    DETAILED DESCRIPTION
- *
- * 	Setup:
- * 	  Setup signal handling.
- *        Make and change to a temporary directory.
- *	  Pause for SIGUSR1 if option specified.
- *        Add TESTPROG variable to the environment
- *
- * 	Test:
- *	 Loop if the proper options are given.
- *	 fork()
- *	 Check return code, if system call failed (return=-1)
- *		Log the errno
- *	   CHILD:
- *              open a temp file
- *		Determine environment values and write to file
- *		close file containing test values.
- *		exit.
- *	    PARENT:
- *		Wait for child to exit.
- *              Verify exit status
- *		Open file containing test values.
- *		For each test case:
- *			Read the value from the file.
- *			Determine and report PASS/FAIL result.
+ * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+/*\
+ *[Description]
  *
- * 	Cleanup:
- * 	  Print errno log and/or timing stats if options given
- *        Remove the temporary directory and exit.
+ * This test verifies that parent process shares environ variables with the
+ * child and that child doesn't change parent's environ variables.
  */
 
 #include <stdlib.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/param.h>
-#include <signal.h>
-#include <errno.h>
-#include "test.h"
-#include "safe_macros.h"
-
-char *TCID = "fork04";
-
-#define	KIDEXIT	42
-#define MAX_LINE_LENGTH 256
-#define OUTPUT_FILE  "env.out"
-#define ENV_NOT_SET  "getenv() does not find variable set"
+#include "tst_test.h"
 
-/* list of environment variables to test */
-char *environ_list[] = { "TERM", "NoTSetzWq", "TESTPROG" };
+#define ENV_KEY "LTP_FORK04"
+#define ENV_VAL0 "PASS"
+#define ENV_VAL1 "FAIL"
 
-#define NUMBER_OF_ENVIRON (sizeof(environ_list)/sizeof(char *))
-int TST_TOTAL = NUMBER_OF_ENVIRON;
-
-static void cleanup(void)
+static void run_child(void)
 {
-	tst_rmdir();
-}
+	const char *val;
 
-static void setup(void)
-{
+	val = getenv(ENV_KEY);
+	if (!val)
+		tst_brk(TBROK, "Can't find %s environ variable", ENV_KEY);
 
-	tst_sig(FORK, DEF_HANDLER, cleanup);
-	TEST_PAUSE;
-	tst_tmpdir();
+	TST_EXP_EXPR(strcmp(ENV_VAL0, val) == 0,
+		"%s environ variable has been inherited by the child",
+		ENV_KEY)
 
-	/* add a variable to the environment */
-	putenv("TESTPROG=FRKTCS04");
-}
+	tst_res(TINFO, "Unset %s environ variable inside child", ENV_KEY);
 
-static void child_environment(void)
-{
-
-	int fildes;
-	int index;
-	char msg[MAX_LINE_LENGTH];
-	char *var;
+	if (unsetenv(ENV_KEY) == -1)
+		tst_brk(TBROK, "Can't unset %s environ variable", ENV_KEY);
 
-	fildes = creat(OUTPUT_FILE, 0700);
+	TST_CHECKPOINT_WAKE_AND_WAIT(0);
 
-	for (index = 0; index < (int)NUMBER_OF_ENVIRON; index++) {
-		memset(msg, 0, MAX_LINE_LENGTH);
+	tst_res(TINFO, "Set %s=%s environ variable inside child", ENV_KEY, ENV_VAL1);
 
-		var = getenv(environ_list[index]);
-		if (var == NULL)
-			(void)sprintf(msg, "%s:%s", environ_list[index],
-				      ENV_NOT_SET);
-		else
-			(void)sprintf(msg, "%s:%s", environ_list[index], var);
-		/* includes extra null chars */
-		write(fildes, msg, sizeof(msg));
-	}
+	SAFE_SETENV(ENV_KEY, ENV_VAL1, 0);
 
-	close(fildes);
+	TST_CHECKPOINT_WAKE(0);
 }
 
-/*
- * Compare parent env string to child's string.
- * Each string is in the format:  <env var>:<value>
- */
-static int cmp_env_strings(char *pstring, char *cstring)
+static void run(void)
 {
-	char *penv, *cenv, *pvalue, *cvalue;
+	const char *val;
 
-	/*
-	 * Break pstring into env and value
-	 */
-	penv = pstring;
-	pvalue = strchr(pstring, ':');
-	if (pvalue == NULL) {
-		tst_resm(TBROK,
-			 "internal error - parent's env string not in correct format:'%s'",
-			 pstring);
-		return -1;
-	} else {
-		*pvalue = '\0';
-		pvalue++;
-		if (*pvalue == '\0') {
-			tst_resm(TBROK,
-				 "internal error - missing parent's env value");
-			return -1;
-		}
-	}
+	tst_res(TINFO,
+		"Set %s=%s environ variable inside parent",
+		ENV_KEY, ENV_VAL0);
 
-	/*
-	 * Break cstring into env and value
-	 */
-	cenv = cstring;
-	cvalue = strchr(cstring, ':');
-	if (cvalue == NULL) {
-		tst_resm(TBROK,
-			 "internal error - parent's env string not in correct format:'%s'",
-			 cstring);
-		return -1;
-	} else {
-		*cvalue = '\0';
-		cvalue++;
-		if (*cvalue == '\0') {
-			tst_resm(TBROK,
-				 "internal error - missing child's env value");
-			return -1;
-		}
-	}
+	SAFE_SETENV(ENV_KEY, ENV_VAL0, 0);
 
-	if (strcmp(penv, cenv) != 0) {
-		tst_resm(TBROK, "internal error - parent(%s) != child (%s) env",
-			 penv, cenv);
-		return -1;
-	}
+	tst_res(TINFO, "Spawning child");
 
-	if (strcmp(pvalue, cvalue) != 0) {
-		tst_resm(TFAIL,
-			 "Env var %s changed after fork(), parent's %s, child's %s",
-			 penv, pvalue, cvalue);
-	} else {
-		tst_resm(TPASS, "Env var %s unchanged after fork(): %s",
-			 penv, cvalue);
+	if (!SAFE_FORK()) {
+		run_child();
+		exit(0);
 	}
-	return 0;
-
-}
-
-/***************************************************************
- * parent_environment - the parent side of the environment tests
- *        determine values for the variables
- *        read the values determined by the child
- *        compare values
- ***************************************************************/
-void parent_environment(void)
-{
-
-	int fildes;
-	char tmp_line[MAX_LINE_LENGTH];
-	char parent_value[MAX_LINE_LENGTH];
-	unsigned int index;
-	int ret;
-	char *var;
-
-	fildes = SAFE_OPEN(cleanup, OUTPUT_FILE, O_RDWR);
-	for (index = 0; index < NUMBER_OF_ENVIRON; index++) {
-		ret = read(fildes, tmp_line, MAX_LINE_LENGTH);
-		if (ret == 0) {
-			tst_resm(TBROK,
-				 "fork() test. parent_environment: failed to read from file with %d (%s)",
-				 errno, strerror(errno));
-		} else {
 
-			var = getenv(environ_list[index]);
-			if (var == NULL)
-				sprintf(parent_value, "%s:%s",
-					environ_list[index], ENV_NOT_SET);
-			else
-				sprintf(parent_value, "%s:%s",
-					environ_list[index], var);
+	TST_CHECKPOINT_WAIT(0);
 
-			cmp_env_strings(parent_value, tmp_line);
-
-		}
+	val = getenv(ENV_KEY);
+	if (!val) {
+		tst_res(TFAIL,
+			"%s environ variable has been unset inside parent",
+			ENV_KEY);
+	} else {
+		TST_EXP_EXPR(strcmp(ENV_VAL0, val) == 0,
+			"%s environ variable is still present inside parent",
+			ENV_KEY)
 	}
 
-	close(fildes);
-}
-
-int main(int ac, char **av)
-{
-	int lc;
-	int kid_status;
-	int wait_status;
-	int fails;
-
-	tst_parse_opts(ac, av, NULL, NULL);
-
-	setup();
-
-	for (lc = 0; TEST_LOOPING(lc); lc++) {
-		tst_count = 0;
-		fails = 0;
-
-		TEST(fork());
-
-		if (TEST_RETURN == -1) {
-			/* fork failed */
-			tst_brkm(TFAIL, cleanup,
-				 "fork() failed with %d (%s)",
-				 TEST_ERRNO, strerror(TEST_ERRNO));
-		} else if (TEST_RETURN == 0) {
-			/* child */
-			/* determine environment variables */
-			child_environment();
-			/* exit with known value */
-			exit(KIDEXIT);
-		} else {
-			/* parent of successful fork */
-			/* wait for the child to complete */
-			wait_status = waitpid(TEST_RETURN, &kid_status, 0);
-			/* validate the child exit status */
-			if (wait_status == TEST_RETURN) {
-				if (kid_status != KIDEXIT << 8) {
-					tst_brkm(TBROK, cleanup,
-						 "fork(): Incorrect child status returned on wait(): %d",
-						 kid_status);
-					fails++;
-				}
-			} else {
-				tst_brkm(TBROK, cleanup,
-					 "fork(): wait() for child status failed with %d errno: %d : %s",
-					 wait_status, errno,
-					 strerror(errno));
-				fails++;
-			}
-
-			if (fails == 0) {
-				/* verification tests */
-				parent_environment();
-			}
-		}
-
+	TST_CHECKPOINT_WAKE_AND_WAIT(0);
+
+	val = getenv(ENV_KEY);
+	if (!val)
+		tst_res(TFAIL,
+			"%s environ variable has been unset inside parent",
+			ENV_KEY);
+	else {
+		TST_EXP_EXPR(strcmp(ENV_VAL0, val) == 0,
+			"%s environ variable didn't change inside parent",
+			ENV_KEY)
 	}
-
-	cleanup();
-	tst_exit();
 }
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.needs_checkpoints = 1,
+};
-- 
2.35.3



More information about the ltp mailing list