1 /* $NetBSD: t_getenv.c,v 1.1 2011/07/07 15:50:23 jruoho Exp $ */ 2 3 /*- 4 * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /*- 36 * Copyright (c) 2010 The NetBSD Foundation, Inc. 37 * All rights reserved. 38 * 39 * This code is derived from software contributed to The NetBSD Foundation 40 * by Matthias Scheler. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 52 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 53 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 54 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 55 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 56 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 57 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 58 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 59 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 60 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 61 * POSSIBILITY OF SUCH DAMAGE. 62 */ 63 #include <sys/cdefs.h> 64 __RCSID("$NetBSD: t_getenv.c,v 1.1 2011/07/07 15:50:23 jruoho Exp $"); 65 66 #include <atf-c.h> 67 #include <errno.h> 68 #include <pthread.h> 69 #include <stdio.h> 70 #include <stdlib.h> 71 #include <string.h> 72 #include <time.h> 73 74 #define THREADED_NUM_THREADS 8 75 #define THREADED_NUM_VARS 16 76 #define THREADED_VAR_NAME "THREADED%zu" 77 #define THREADED_RUN_TIME 10 78 79 extern char **environ; 80 static void *thread_getenv_r(void *); 81 static void *thread_putenv(void *); 82 static void *thread_setenv(void *); 83 static void *thread_unsetenv(void *); 84 85 static void * 86 thread_getenv_r(void *arg) 87 { 88 time_t endtime; 89 90 endtime = *(time_t *)arg; 91 do { 92 size_t i; 93 char name[32], value[128]; 94 95 i = lrand48() % THREADED_NUM_VARS; 96 (void)snprintf(name, sizeof(name), THREADED_VAR_NAME, i); 97 98 if (getenv_r(name, value, sizeof(value)) == -1) { 99 ATF_CHECK(errno == ENOENT); 100 } 101 } while (time(NULL) < endtime); 102 103 return NULL; 104 } 105 106 107 static void * 108 thread_putenv(void *arg) 109 { 110 time_t endtime; 111 size_t i; 112 static char vars[THREADED_NUM_VARS][128]; 113 114 for (i = 0; i < THREADED_NUM_VARS; i++) { 115 (void)snprintf(vars[i], sizeof(vars[i]), 116 THREADED_VAR_NAME "=putenv %ld", i, lrand48()); 117 } 118 119 endtime = *(time_t *)arg; 120 do { 121 char name[128]; 122 123 i = lrand48() % THREADED_NUM_VARS; 124 (void)strlcpy(name, vars[i], sizeof(name)); 125 *strchr(name, '=') = '\0'; 126 127 ATF_CHECK(unsetenv(name) != -1); 128 ATF_CHECK(putenv(vars[i]) != -1); 129 } while (time(NULL) < endtime); 130 131 return NULL; 132 } 133 134 static void * 135 thread_setenv(void *arg) 136 { 137 time_t endtime; 138 139 endtime = *(time_t *)arg; 140 do { 141 size_t i; 142 char name[32], value[64]; 143 144 i = lrand48() % THREADED_NUM_VARS; 145 (void)snprintf(name, sizeof(name), THREADED_VAR_NAME, i); 146 (void)snprintf(value, sizeof(value), "setenv %ld", lrand48()); 147 148 ATF_CHECK(setenv(name, value, 1) != -1); 149 } while (time(NULL) < endtime); 150 151 return NULL; 152 } 153 154 static void * 155 thread_unsetenv(void *arg) 156 { 157 time_t endtime; 158 159 endtime = *(time_t *)arg; 160 do { 161 size_t i; 162 char name[32]; 163 164 i = lrand48() % THREADED_NUM_VARS; 165 (void)snprintf(name, sizeof(name), THREADED_VAR_NAME, i); 166 167 ATF_CHECK(unsetenv(name) != -1); 168 } while (time(NULL) < endtime); 169 170 return NULL; 171 } 172 173 ATF_TC(clearenv_basic); 174 ATF_TC_HEAD(clearenv_basic, tc) 175 { 176 atf_tc_set_md_var(tc, "descr", 177 "Test user clearing environment directly"); 178 } 179 180 ATF_TC_BODY(clearenv_basic, tc) 181 { 182 char name[1024], value[1024]; 183 184 for (size_t i = 0; i < 1024; i++) { 185 snprintf(name, sizeof(name), "crap%zu", i); 186 snprintf(value, sizeof(value), "%zu", i); 187 ATF_CHECK(setenv(name, value, 1) != -1); 188 } 189 190 *environ = NULL; 191 192 for (size_t i = 0; i < 1; i++) { 193 snprintf(name, sizeof(name), "crap%zu", i); 194 snprintf(value, sizeof(value), "%zu", i); 195 ATF_CHECK(setenv(name, value, 1) != -1); 196 } 197 198 ATF_CHECK_STREQ(getenv("crap0"), "0"); 199 ATF_CHECK(getenv("crap1") == NULL); 200 ATF_CHECK(getenv("crap2") == NULL); 201 } 202 203 ATF_TC(getenv_basic); 204 ATF_TC_HEAD(getenv_basic, tc) 205 { 206 atf_tc_set_md_var(tc, "descr", 207 "Test setenv(3), getenv(3)"); 208 } 209 210 ATF_TC_BODY(getenv_basic, tc) 211 { 212 ATF_CHECK(setenv("EVIL", "very=bad", 1) != -1); 213 ATF_CHECK_STREQ(getenv("EVIL"), "very=bad"); 214 ATF_CHECK(getenv("EVIL=very") == NULL); 215 ATF_CHECK(unsetenv("EVIL") != -1); 216 } 217 218 ATF_TC(getenv_r_thread); 219 ATF_TC_HEAD(getenv_r_thread, tc) 220 { 221 char timeout[32]; 222 223 atf_tc_set_md_var(tc, "descr", "Test getenv_r(3) with threads"); 224 225 (void)snprintf(timeout, sizeof(timeout), "%d", THREADED_RUN_TIME + 5); 226 227 atf_tc_set_md_var(tc, "timeout", timeout); 228 } 229 230 ATF_TC_BODY(getenv_r_thread, tc) 231 { 232 pthread_t threads[THREADED_NUM_THREADS]; 233 time_t endtime; 234 size_t i, j; 235 236 endtime = time(NULL) + THREADED_RUN_TIME; 237 238 for (i = j = 0; j < 2; j++) { 239 240 ATF_CHECK(pthread_create(&threads[i++], NULL, thread_getenv_r, 241 &endtime) == 0); 242 } 243 244 for (j = 0; j < i; j++) 245 ATF_CHECK(pthread_join(threads[j], NULL) == 0); 246 } 247 248 ATF_TC(putenv_basic); 249 ATF_TC_HEAD(putenv_basic, tc) 250 { 251 atf_tc_set_md_var(tc, "descr", 252 "Test putenv(3), getenv(3), unsetenv(3)"); 253 } 254 255 256 ATF_TC_BODY(putenv_basic, tc) 257 { 258 char string[1024]; 259 260 snprintf(string, sizeof(string), "crap=true"); 261 ATF_CHECK(putenv(string) != -1); 262 ATF_CHECK_STREQ(getenv("crap"), "true"); 263 string[1] = 'l'; 264 ATF_CHECK_STREQ(getenv("clap"), "true"); 265 ATF_CHECK(getenv("crap") == NULL); 266 string[1] = 'r'; 267 ATF_CHECK(unsetenv("crap") != -1); 268 ATF_CHECK(getenv("crap") == NULL); 269 270 ATF_CHECK_ERRNO(EINVAL, putenv(NULL) == -1); 271 ATF_CHECK_ERRNO(EINVAL, putenv(__UNCONST("val")) == -1); 272 ATF_CHECK_ERRNO(EINVAL, putenv(__UNCONST("=val")) == -1); 273 } 274 275 ATF_TC(putenv_thread); 276 ATF_TC_HEAD(putenv_thread, tc) 277 { 278 char timeout[32]; 279 280 atf_tc_set_md_var(tc, "descr", "Test concurrent access by putenv(3)"); 281 282 (void)snprintf(timeout, sizeof(timeout), "%d", THREADED_RUN_TIME + 5); 283 284 atf_tc_set_md_var(tc, "timeout", timeout); 285 } 286 287 ATF_TC_BODY(putenv_thread, tc) 288 { 289 pthread_t threads[THREADED_NUM_THREADS]; 290 time_t endtime; 291 size_t i, j; 292 293 endtime = time(NULL) + THREADED_RUN_TIME; 294 295 for (i = j = 0; j < 2; j++) { 296 297 ATF_CHECK(pthread_create(&threads[i++], NULL, thread_putenv, 298 &endtime) == 0); 299 } 300 301 for (j = 0; j < i; j++) 302 ATF_CHECK(pthread_join(threads[j], NULL) == 0); 303 } 304 305 ATF_TC(setenv_basic); 306 ATF_TC_HEAD(setenv_basic, tc) 307 { 308 atf_tc_set_md_var(tc, "descr", 309 "Test setenv(3), getenv(3), unsetenv(3)"); 310 atf_tc_set_md_var(tc, "timeout", "300"); 311 } 312 313 ATF_TC_BODY(setenv_basic, tc) 314 { 315 const size_t numvars = 8192; 316 size_t i, offset; 317 char name[1024]; 318 char value[1024]; 319 320 offset = lrand48(); 321 for (i = 0; i < numvars; i++) { 322 (void)snprintf(name, sizeof(name), "var%zu", 323 (i * 7 + offset) % numvars); 324 (void)snprintf(value, sizeof(value), "value%ld", lrand48()); 325 ATF_CHECK(setenv(name, value, 1) != -1); 326 ATF_CHECK(setenv(name, "foo", 0) != -1); 327 ATF_CHECK_STREQ(getenv(name), value); 328 } 329 330 offset = lrand48(); 331 for (i = 0; i < numvars; i++) { 332 (void)snprintf(name, sizeof(name), "var%zu", 333 (i * 11 + offset) % numvars); 334 ATF_CHECK(unsetenv(name) != -1); 335 ATF_CHECK(getenv(name) == NULL); 336 ATF_CHECK(unsetenv(name) != -1); 337 } 338 339 ATF_CHECK_ERRNO(EINVAL, setenv(NULL, "val", 1) == -1); 340 ATF_CHECK_ERRNO(EINVAL, setenv("", "val", 1) == -1); 341 ATF_CHECK_ERRNO(EINVAL, setenv("v=r", "val", 1) == -1); 342 ATF_CHECK_ERRNO(EINVAL, setenv("var", NULL, 1) == -1); 343 344 ATF_CHECK(setenv("var", "=val", 1) == 0); 345 ATF_CHECK_STREQ(getenv("var"), "=val"); 346 } 347 348 ATF_TC(setenv_mixed); 349 ATF_TC_HEAD(setenv_mixed, tc) 350 { 351 atf_tc_set_md_var(tc, "descr", 352 "Test mixing setenv(3), unsetenv(3) and putenv(3)"); 353 } 354 355 356 ATF_TC_BODY(setenv_mixed, tc) 357 { 358 char string[32]; 359 360 (void)strcpy(string, "mixedcrap=putenv"); 361 362 ATF_CHECK(setenv("mixedcrap", "setenv", 1) != -1); 363 ATF_CHECK_STREQ(getenv("mixedcrap"), "setenv"); 364 ATF_CHECK(putenv(string) != -1); 365 ATF_CHECK_STREQ(getenv("mixedcrap"), "putenv"); 366 ATF_CHECK(unsetenv("mixedcrap") != -1); 367 ATF_CHECK(getenv("mixedcrap") == NULL); 368 369 ATF_CHECK(putenv(string) != -1); 370 ATF_CHECK_STREQ(getenv("mixedcrap"), "putenv"); 371 ATF_CHECK(setenv("mixedcrap", "setenv", 1) != -1); 372 ATF_CHECK_STREQ(getenv("mixedcrap"), "setenv"); 373 ATF_CHECK(unsetenv("mixedcrap") != -1); 374 ATF_CHECK(getenv("mixedcrap") == NULL); 375 } 376 377 ATF_TC(setenv_thread); 378 ATF_TC_HEAD(setenv_thread, tc) 379 { 380 char timeout[32]; 381 382 atf_tc_set_md_var(tc, "descr", "Test concurrent access by setenv(3)"); 383 384 (void)snprintf(timeout, sizeof(timeout), "%d", THREADED_RUN_TIME + 5); 385 386 atf_tc_set_md_var(tc, "timeout", timeout); 387 } 388 389 ATF_TC_BODY(setenv_thread, tc) 390 { 391 pthread_t threads[THREADED_NUM_THREADS]; 392 time_t endtime; 393 size_t i, j; 394 395 endtime = time(NULL) + THREADED_RUN_TIME; 396 397 for (i = j = 0; j < 2; j++) { 398 399 ATF_CHECK(pthread_create(&threads[i++], NULL, thread_setenv, 400 &endtime) == 0); 401 } 402 403 for (j = 0; j < i; j++) 404 ATF_CHECK(pthread_join(threads[j], NULL) == 0); 405 } 406 407 ATF_TC(unsetenv_thread); 408 ATF_TC_HEAD(unsetenv_thread, tc) 409 { 410 char timeout[32]; 411 412 atf_tc_set_md_var(tc, "descr", "Test unsetenv(3) with threads"); 413 414 (void)snprintf(timeout, sizeof(timeout), "%d", THREADED_RUN_TIME + 5); 415 416 atf_tc_set_md_var(tc, "timeout", timeout); 417 } 418 419 ATF_TC_BODY(unsetenv_thread, tc) 420 { 421 pthread_t threads[THREADED_NUM_THREADS]; 422 time_t endtime; 423 size_t i, j; 424 425 endtime = time(NULL) + THREADED_RUN_TIME; 426 427 for (i = j = 0; j < 2; j++) { 428 429 ATF_CHECK(pthread_create(&threads[i++], NULL, thread_unsetenv, 430 &endtime) == 0); 431 } 432 433 for (j = 0; j < i; j++) 434 ATF_CHECK(pthread_join(threads[j], NULL) == 0); 435 } 436 437 ATF_TP_ADD_TCS(tp) 438 { 439 ATF_TP_ADD_TC(tp, clearenv_basic); 440 ATF_TP_ADD_TC(tp, getenv_basic); 441 ATF_TP_ADD_TC(tp, getenv_r_thread); 442 ATF_TP_ADD_TC(tp, putenv_basic); 443 ATF_TP_ADD_TC(tp, putenv_thread); 444 ATF_TP_ADD_TC(tp, setenv_basic); 445 ATF_TP_ADD_TC(tp, setenv_mixed); 446 ATF_TP_ADD_TC(tp, setenv_thread); 447 ATF_TP_ADD_TC(tp, unsetenv_thread); 448 449 return atf_no_error(); 450 } 451