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