• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
107 char *TCID = "fork04";
108 
109 #define	KIDEXIT	42
110 #define MAX_LINE_LENGTH 256
111 #define OUTPUT_FILE  "env.out"
112 #define ENV_NOT_SET  "getenv() does not find variable set"
113 
114 /* list of environment variables to test */
115 char *environ_list[] = { "TERM", "NoTSetzWq", "TESTPROG" };
116 
117 #define NUMBER_OF_ENVIRON (sizeof(environ_list)/sizeof(char *))
118 int TST_TOTAL = NUMBER_OF_ENVIRON;
119 
cleanup(void)120 static void cleanup(void)
121 {
122 	tst_rmdir();
123 }
124 
setup(void)125 static void setup(void)
126 {
127 
128 	tst_sig(FORK, DEF_HANDLER, cleanup);
129 	TEST_PAUSE;
130 	tst_tmpdir();
131 
132 	/* add a variable to the environment */
133 	putenv("TESTPROG=FRKTCS04");
134 }
135 
child_environment(void)136 static void child_environment(void)
137 {
138 
139 	int fildes;
140 	int index;
141 	char msg[MAX_LINE_LENGTH];
142 	char *var;
143 
144 	fildes = creat(OUTPUT_FILE, 0700);
145 
146 	for (index = 0; index < NUMBER_OF_ENVIRON; index++) {
147 		memset(msg, 0, MAX_LINE_LENGTH);
148 
149 		var = getenv(environ_list[index]);
150 		if (var == NULL)
151 			(void)sprintf(msg, "%s:%s", environ_list[index],
152 				      ENV_NOT_SET);
153 		else
154 			(void)sprintf(msg, "%s:%s", environ_list[index], var);
155 		/* includes extra null chars */
156 		write(fildes, msg, sizeof(msg));
157 	}
158 
159 	close(fildes);
160 }
161 
162 /*
163  * Compare parent env string to child's string.
164  * Each string is in the format:  <env var>:<value>
165  */
cmp_env_strings(char * pstring,char * cstring)166 static int cmp_env_strings(char *pstring, char *cstring)
167 {
168 	char *penv, *cenv, *pvalue, *cvalue;
169 
170 	/*
171 	 * Break pstring into env and value
172 	 */
173 	penv = pstring;
174 	pvalue = strchr(pstring, ':');
175 	if (pvalue == NULL) {
176 		tst_resm(TBROK,
177 			 "internal error - parent's env string not in correct format:'%s'",
178 			 pstring);
179 		return -1;
180 	} else {
181 		*pvalue = '\0';
182 		pvalue++;
183 		if (*pvalue == '\0') {
184 			tst_resm(TBROK,
185 				 "internal error - missing parent's env value");
186 			return -1;
187 		}
188 	}
189 
190 	/*
191 	 * Break cstring into env and value
192 	 */
193 	cenv = cstring;
194 	cvalue = strchr(cstring, ':');
195 	if (cvalue == NULL) {
196 		tst_resm(TBROK,
197 			 "internal error - parent's env string not in correct format:'%s'",
198 			 cstring);
199 		return -1;
200 	} else {
201 		*cvalue = '\0';
202 		cvalue++;
203 		if (*cvalue == '\0') {
204 			tst_resm(TBROK,
205 				 "internal error - missing child's env value");
206 			return -1;
207 		}
208 	}
209 
210 	if (strcmp(penv, cenv) != 0) {
211 		tst_resm(TBROK, "internal error - parent(%s) != child (%s) env",
212 			 penv, cenv);
213 		return -1;
214 	}
215 
216 	if (strcmp(pvalue, cvalue) != 0) {
217 		tst_resm(TFAIL,
218 			 "Env var %s changed after fork(), parent's %s, child's %s",
219 			 penv, pvalue, cvalue);
220 	} else {
221 		tst_resm(TPASS, "Env var %s unchanged after fork(): %s",
222 			 penv, cvalue);
223 	}
224 	return 0;
225 
226 }
227 
228 /***************************************************************
229  * parent_environment - the parent side of the environment tests
230  *        determine values for the variables
231  *        read the values determined by the child
232  *        compare values
233  ***************************************************************/
parent_environment(void)234 void parent_environment(void)
235 {
236 
237 	int fildes;
238 	char tmp_line[MAX_LINE_LENGTH];
239 	char parent_value[MAX_LINE_LENGTH];
240 	int index;
241 	int ret;
242 	char *var;
243 
244 	fildes = open(OUTPUT_FILE, O_RDWR);
245 	if (fildes == -1) {
246 		tst_brkm(TBROK, cleanup,
247 			 "fork() test. Parent open of temporary file failed. errno %d (%s)\n",
248 			 errno, strerror(errno));
249 	}
250 	for (index = 0; index < NUMBER_OF_ENVIRON; index++) {
251 		ret = read(fildes, tmp_line, MAX_LINE_LENGTH);
252 		if (ret == 0) {
253 			tst_resm(TBROK,
254 				 "fork() test. parent_environment: failed to read from file with %d (%s)",
255 				 errno, strerror(errno));
256 		} else {
257 
258 			var = getenv(environ_list[index]);
259 			if (var == NULL)
260 				sprintf(parent_value, "%s:%s",
261 					environ_list[index], ENV_NOT_SET);
262 			else
263 				sprintf(parent_value, "%s:%s",
264 					environ_list[index], var);
265 
266 			cmp_env_strings(parent_value, tmp_line);
267 
268 		}
269 	}
270 
271 	close(fildes);
272 }
273 
main(int ac,char ** av)274 int main(int ac, char **av)
275 {
276 	int lc;
277 	int kid_status;
278 	int wait_status;
279 	int fails;
280 
281 	tst_parse_opts(ac, av, NULL, NULL);
282 
283 	setup();
284 
285 	for (lc = 0; TEST_LOOPING(lc); lc++) {
286 		tst_count = 0;
287 		fails = 0;
288 
289 		TEST(fork());
290 
291 		if (TEST_RETURN == -1) {
292 			/* fork failed */
293 			tst_brkm(TFAIL, cleanup,
294 				 "fork() failed with %d (%s)",
295 				 TEST_ERRNO, strerror(TEST_ERRNO));
296 		} else if (TEST_RETURN == 0) {
297 			/* child */
298 			/* determine environment variables */
299 			child_environment();
300 			/* exit with known value */
301 			exit(KIDEXIT);
302 		} else {
303 			/* parent of successful fork */
304 			/* wait for the child to complete */
305 			wait_status = waitpid(TEST_RETURN, &kid_status, 0);
306 			/* validate the child exit status */
307 			if (wait_status == TEST_RETURN) {
308 				if (kid_status != KIDEXIT << 8) {
309 					tst_brkm(TBROK, cleanup,
310 						 "fork(): Incorrect child status returned on wait(): %d",
311 						 kid_status);
312 					fails++;
313 				}
314 			} else {
315 				tst_brkm(TBROK, cleanup,
316 					 "fork(): wait() for child status failed with %d errno: %d : %s",
317 					 wait_status, errno,
318 					 strerror(errno));
319 				fails++;
320 			}
321 
322 			if (fails == 0) {
323 				/* verification tests */
324 				parent_environment();
325 			}
326 		}
327 
328 	}
329 
330 	cleanup();
331 	tst_exit();
332 }
333