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