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
cleanup(void)121 static void cleanup(void)
122 {
123 tst_rmdir();
124 }
125
setup(void)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
child_environment(void)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 */
cmp_env_strings(char * pstring,char * cstring)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 ***************************************************************/
parent_environment(void)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
main(int ac,char ** av)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