Home | History | Annotate | Line # | Download | only in stdlib
t_getenv.c revision 1.1
      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