Home | History | Annotate | Download | only in fork
      1 /*
      2  * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
      3  *
      4  * This program is free software; you can redistribute it and/or modify it
      5  * under the terms of version 2 of the GNU General Public License as
      6  * published by the Free Software Foundation.
      7  *
      8  * This program is distributed in the hope that it would be useful, but
      9  * WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     11  *
     12  * Further, this software is distributed without any warranty that it is
     13  * free of the rightful claim of any third person regarding infringement
     14  * or the like.  Any license provided herein, whether implied or
     15  * otherwise, applies only to this software file.  Patent licenses, if
     16  * any, provided herein do not apply to combinations of this program with
     17  * other software, or any other product whatsoever.
     18  *
     19  * You should have received a copy of the GNU General Public License along
     20  * with this program; if not, write the Free Software Foundation, Inc.,
     21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     22  *
     23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
     24  * Mountain View, CA  94043, or:
     25  *
     26  * http://www.sgi.com
     27  *
     28  * For further information regarding this notice, see:
     29  *
     30  * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
     31  *
     32  *
     33  *    OS Test - Silicon Graphics, Inc.
     34  *    TEST IDENTIFIER	: fork04
     35  *    TEST TITLE	: Child inheritance of Environment Variables after fork()
     36  *    PARENT DOCUMENT	: frktds01
     37  *    TEST CASE TOTAL	: 3
     38  *    WALL CLOCK TIME	: 1
     39  *    CPU TYPES		: ALL
     40  *    AUTHOR		: Kathy Olmsted
     41  *    CO-PILOT		: Steve Shaw
     42  *    DATE STARTED	: 06/17/92
     43  *    INITIAL RELEASE	: UNICOS 7.0
     44  *
     45  *    TEST CASES
     46  *       Test these environment variables correctly inherited by child:
     47  *       1. TERM
     48  *       2. NoTSetzWq
     49  *       3. TESTPROG
     50  *
     51  *    INPUT SPECIFICATIONS
     52  * 	The standard options for system call tests are accepted.
     53  *	(See the parse_opts(3) man page).
     54  *
     55  *    DURATION
     56  * 	Terminates - with frequency and infinite modes.
     57  *
     58  *    SIGNALS
     59  * 	Uses SIGUSR1 to pause before test if option set.
     60  * 	(See the parse_opts(3) man page).
     61  *
     62  *    ENVIRONMENTAL NEEDS
     63  *      No run-time environmental needs.
     64  *
     65  *    DETAILED DESCRIPTION
     66  *
     67  * 	Setup:
     68  * 	  Setup signal handling.
     69  *        Make and change to a temporary directory.
     70  *	  Pause for SIGUSR1 if option specified.
     71  *        Add TESTPROG variable to the environment
     72  *
     73  * 	Test:
     74  *	 Loop if the proper options are given.
     75  *	 fork()
     76  *	 Check return code, if system call failed (return=-1)
     77  *		Log the errno
     78  *	   CHILD:
     79  *              open a temp file
     80  *		Determine environment values and write to file
     81  *		close file containing test values.
     82  *		exit.
     83  *	    PARENT:
     84  *		Wait for child to exit.
     85  *              Verify exit status
     86  *		Open file containing test values.
     87  *		For each test case:
     88  *			Read the value from the file.
     89  *			Determine and report PASS/FAIL result.
     90  *
     91  * 	Cleanup:
     92  * 	  Print errno log and/or timing stats if options given
     93  *        Remove the temporary directory and exit.
     94  */
     95 
     96 #include <stdlib.h>
     97 #include <sys/types.h>
     98 #include <sys/wait.h>
     99 #include <unistd.h>
    100 #include <fcntl.h>
    101 #include <string.h>
    102 #include <sys/param.h>
    103 #include <signal.h>
    104 #include <errno.h>
    105 #include "test.h"
    106 #include "safe_macros.h"
    107 
    108 char *TCID = "fork04";
    109 
    110 #define	KIDEXIT	42
    111 #define MAX_LINE_LENGTH 256
    112 #define OUTPUT_FILE  "env.out"
    113 #define ENV_NOT_SET  "getenv() does not find variable set"
    114 
    115 /* list of environment variables to test */
    116 char *environ_list[] = { "TERM", "NoTSetzWq", "TESTPROG" };
    117 
    118 #define NUMBER_OF_ENVIRON (sizeof(environ_list)/sizeof(char *))
    119 int TST_TOTAL = NUMBER_OF_ENVIRON;
    120 
    121 static void cleanup(void)
    122 {
    123 	tst_rmdir();
    124 }
    125 
    126 static void setup(void)
    127 {
    128 
    129 	tst_sig(FORK, DEF_HANDLER, cleanup);
    130 	TEST_PAUSE;
    131 	tst_tmpdir();
    132 
    133 	/* add a variable to the environment */
    134 	putenv("TESTPROG=FRKTCS04");
    135 }
    136 
    137 static void child_environment(void)
    138 {
    139 
    140 	int fildes;
    141 	int index;
    142 	char msg[MAX_LINE_LENGTH];
    143 	char *var;
    144 
    145 	fildes = creat(OUTPUT_FILE, 0700);
    146 
    147 	for (index = 0; index < NUMBER_OF_ENVIRON; index++) {
    148 		memset(msg, 0, MAX_LINE_LENGTH);
    149 
    150 		var = getenv(environ_list[index]);
    151 		if (var == NULL)
    152 			(void)sprintf(msg, "%s:%s", environ_list[index],
    153 				      ENV_NOT_SET);
    154 		else
    155 			(void)sprintf(msg, "%s:%s", environ_list[index], var);
    156 		/* includes extra null chars */
    157 		write(fildes, msg, sizeof(msg));
    158 	}
    159 
    160 	close(fildes);
    161 }
    162 
    163 /*
    164  * Compare parent env string to child's string.
    165  * Each string is in the format:  <env var>:<value>
    166  */
    167 static int cmp_env_strings(char *pstring, char *cstring)
    168 {
    169 	char *penv, *cenv, *pvalue, *cvalue;
    170 
    171 	/*
    172 	 * Break pstring into env and value
    173 	 */
    174 	penv = pstring;
    175 	pvalue = strchr(pstring, ':');
    176 	if (pvalue == NULL) {
    177 		tst_resm(TBROK,
    178 			 "internal error - parent's env string not in correct format:'%s'",
    179 			 pstring);
    180 		return -1;
    181 	} else {
    182 		*pvalue = '\0';
    183 		pvalue++;
    184 		if (*pvalue == '\0') {
    185 			tst_resm(TBROK,
    186 				 "internal error - missing parent's env value");
    187 			return -1;
    188 		}
    189 	}
    190 
    191 	/*
    192 	 * Break cstring into env and value
    193 	 */
    194 	cenv = cstring;
    195 	cvalue = strchr(cstring, ':');
    196 	if (cvalue == NULL) {
    197 		tst_resm(TBROK,
    198 			 "internal error - parent's env string not in correct format:'%s'",
    199 			 cstring);
    200 		return -1;
    201 	} else {
    202 		*cvalue = '\0';
    203 		cvalue++;
    204 		if (*cvalue == '\0') {
    205 			tst_resm(TBROK,
    206 				 "internal error - missing child's env value");
    207 			return -1;
    208 		}
    209 	}
    210 
    211 	if (strcmp(penv, cenv) != 0) {
    212 		tst_resm(TBROK, "internal error - parent(%s) != child (%s) env",
    213 			 penv, cenv);
    214 		return -1;
    215 	}
    216 
    217 	if (strcmp(pvalue, cvalue) != 0) {
    218 		tst_resm(TFAIL,
    219 			 "Env var %s changed after fork(), parent's %s, child's %s",
    220 			 penv, pvalue, cvalue);
    221 	} else {
    222 		tst_resm(TPASS, "Env var %s unchanged after fork(): %s",
    223 			 penv, cvalue);
    224 	}
    225 	return 0;
    226 
    227 }
    228 
    229 /***************************************************************
    230  * parent_environment - the parent side of the environment tests
    231  *        determine values for the variables
    232  *        read the values determined by the child
    233  *        compare values
    234  ***************************************************************/
    235 void parent_environment(void)
    236 {
    237 
    238 	int fildes;
    239 	char tmp_line[MAX_LINE_LENGTH];
    240 	char parent_value[MAX_LINE_LENGTH];
    241 	int index;
    242 	int ret;
    243 	char *var;
    244 
    245 	fildes = SAFE_OPEN(cleanup, OUTPUT_FILE, O_RDWR);
    246 	for (index = 0; index < NUMBER_OF_ENVIRON; index++) {
    247 		ret = read(fildes, tmp_line, MAX_LINE_LENGTH);
    248 		if (ret == 0) {
    249 			tst_resm(TBROK,
    250 				 "fork() test. parent_environment: failed to read from file with %d (%s)",
    251 				 errno, strerror(errno));
    252 		} else {
    253 
    254 			var = getenv(environ_list[index]);
    255 			if (var == NULL)
    256 				sprintf(parent_value, "%s:%s",
    257 					environ_list[index], ENV_NOT_SET);
    258 			else
    259 				sprintf(parent_value, "%s:%s",
    260 					environ_list[index], var);
    261 
    262 			cmp_env_strings(parent_value, tmp_line);
    263 
    264 		}
    265 	}
    266 
    267 	close(fildes);
    268 }
    269 
    270 int main(int ac, char **av)
    271 {
    272 	int lc;
    273 	int kid_status;
    274 	int wait_status;
    275 	int fails;
    276 
    277 	tst_parse_opts(ac, av, NULL, NULL);
    278 
    279 	setup();
    280 
    281 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    282 		tst_count = 0;
    283 		fails = 0;
    284 
    285 		TEST(fork());
    286 
    287 		if (TEST_RETURN == -1) {
    288 			/* fork failed */
    289 			tst_brkm(TFAIL, cleanup,
    290 				 "fork() failed with %d (%s)",
    291 				 TEST_ERRNO, strerror(TEST_ERRNO));
    292 		} else if (TEST_RETURN == 0) {
    293 			/* child */
    294 			/* determine environment variables */
    295 			child_environment();
    296 			/* exit with known value */
    297 			exit(KIDEXIT);
    298 		} else {
    299 			/* parent of successful fork */
    300 			/* wait for the child to complete */
    301 			wait_status = waitpid(TEST_RETURN, &kid_status, 0);
    302 			/* validate the child exit status */
    303 			if (wait_status == TEST_RETURN) {
    304 				if (kid_status != KIDEXIT << 8) {
    305 					tst_brkm(TBROK, cleanup,
    306 						 "fork(): Incorrect child status returned on wait(): %d",
    307 						 kid_status);
    308 					fails++;
    309 				}
    310 			} else {
    311 				tst_brkm(TBROK, cleanup,
    312 					 "fork(): wait() for child status failed with %d errno: %d : %s",
    313 					 wait_status, errno,
    314 					 strerror(errno));
    315 				fails++;
    316 			}
    317 
    318 			if (fails == 0) {
    319 				/* verification tests */
    320 				parent_environment();
    321 			}
    322 		}
    323 
    324 	}
    325 
    326 	cleanup();
    327 	tst_exit();
    328 }
    329