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