]> ruderich.org/simon Gitweb - coloredstderr/coloredstderr.git/blob - tests/example_exec.c
update copyright year
[coloredstderr/coloredstderr.git] / tests / example_exec.c
1 /*
2  * Test execve() and exec*() functions.
3  *
4  * Copyright (C) 2013-2015  Simon Ruderich
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21
22 /* For execvpe(). */
23 #define _GNU_SOURCE
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include "example.h"
31 #include "../src/compiler.h"
32
33
34 #define MAGIC "@RUN_"
35 #define MAGIC_LENGTH (strlen(MAGIC))
36
37 #define SETUP_RUN(number) \
38         sprintf(argv0, "%s" MAGIC "%03d", argv[0], (number))
39
40
41 extern char **environ;
42
43
44 static int find_magic_run_number(char *argv0, int *number) {
45     size_t length = strlen(argv0);
46     if (length <= MAGIC_LENGTH + 3) {
47         return 0;
48     }
49     /* Check if the string ends with "@RUN_YYY" where YYY should be a number
50      * (not checked). */
51     argv0 += length - MAGIC_LENGTH - 3;
52     if (strncmp(argv0, MAGIC, MAGIC_LENGTH)) {
53         return 0;
54     }
55     *number = atoi(argv0 + MAGIC_LENGTH);
56
57     /* Strip off "@RUN_YYY". */
58     argv0[0] = 0;
59     return 1;
60 }
61
62 static int cmp(void const *a, void const *b) {
63     return strcmp(*(char * const *)a, *(char * const *)b);
64 }
65 static void dump(char *argv[]) {
66     size_t i;
67
68     i = 0;
69     while (*argv) {
70         printf("argv[%zu] = |%s|\n", i++, *argv++);
71     }
72
73     /* Order of environment variables is not defined, sort them for consistent
74      * test results. */
75     i = 0;
76     char **env = environ;
77     while (*env++) {
78         i++;
79     }
80     qsort(environ, i, sizeof(*env), cmp);
81
82     i = 0;
83     env = environ;
84     while (*env) {
85         /* Skip LD_PRELOAD which contains system dependent values. */
86         if (strncmp(*env, "LD_PRELOAD=", 11)) {
87             printf("environ[%zu] = |%s|\n", i++, *env);
88         }
89         env++;
90     }
91     printf("\n");
92     /* When not writing to stdout (e.g. redirection while testing), glibc is
93      * buffering heavily. Flush to display the output before the exec*(). */
94     fflush(stdout);
95 }
96
97
98 int main(int argc unused, char **argv) {
99     char argv0[strlen(argv[0]) + MAGIC_LENGTH + 3 + 1];
100
101     char *old_ldpreload = getenv("LD_PRELOAD");
102     size_t ldpreload_length = strlen("LD_PRELOAD=") + 1;
103     if (old_ldpreload) {
104         ldpreload_length += strlen(old_ldpreload);
105     }
106     char ldpreload[ldpreload_length];
107     strcpy(ldpreload, "LD_PRELOAD=");
108     if (old_ldpreload) {
109         strcat(ldpreload, old_ldpreload);
110     }
111
112     int run;
113
114     /* First call. */
115     if (!find_magic_run_number(argv[0], &run)) {
116         SETUP_RUN(1);
117
118         char *args[] = { argv0, NULL };
119         char *envp[] = { ldpreload, NULL };
120
121         execve(argv[0], args, envp);
122         return EXIT_FAILURE;
123     }
124
125     /* Following calls, each testing an exec*() feature. */
126
127     dump(argv);
128     SETUP_RUN(run + 1);
129
130     int skip = run - 1;
131
132
133     /* Check that we update/insert the environment correctly. */
134
135     if (!skip--) {
136         printf("\nCHECKING COLORING.\n\n");
137         fflush(stdout);
138
139         xdup2(2, 3);
140
141         char *args[] = { argv0, NULL };
142         char *envp[] = { ldpreload, NULL };
143
144         execve(argv[0], args, envp);
145         return EXIT_FAILURE;
146     } else if (!skip--) {
147         xdup2(2, 4);
148
149         execl(argv[0], argv0, NULL);
150         return EXIT_FAILURE;
151     } else if (!skip--) {
152         xdup2(2, 5);
153
154         execlp(argv[0], argv0, NULL);
155         return EXIT_FAILURE;
156     } else if (!skip--) {
157         xdup2(2, 6);
158
159         char *envp[] = { ldpreload, NULL };
160
161         execle(argv[0], argv0, NULL, envp);
162         return EXIT_FAILURE;
163     } else if (!skip--) {
164         xdup2(2, 7);
165
166         /* Test closing a few descriptors. */
167         close(5);
168         close(6);
169
170         char *args[] = { argv0, NULL };
171
172         execv(argv[0], args);
173         return EXIT_FAILURE;
174     } else if (!skip--) {
175         xdup2(2, 8);
176
177         /* And a few more. */
178         close(7);
179         close(4);
180
181         char *args[] = { argv0, NULL };
182
183         execvp(argv[0], args);
184         return EXIT_FAILURE;
185
186     /* Test handling of COLORED_STDERR_FDS. */
187
188     } else if (!skip--) {
189         /* And the rest. */
190         close(3);
191         close(8);
192
193         xdup2(2, 5);
194
195         char *args[] = { argv0, NULL };
196         char *envp[] = { ldpreload, "COLORED_STDERR_FDS=5,", NULL };
197
198         execve(argv[0], args, envp);
199         return EXIT_FAILURE;
200     } else if (!skip--) {
201         char *args[] = { argv0, NULL };
202         char *envp[] = { ldpreload, NULL };
203
204         xdup2(5, 6);
205         close(5);
206
207         execve(argv[0], args, envp);
208         return EXIT_FAILURE;
209     } else if (!skip--) {
210         close(6);
211
212         char *args[] = { argv0, NULL };
213         setenv("COLORED_STDERR_FDS", "2,", 1);
214
215         execv(argv[0], args);
216         return EXIT_FAILURE;
217     }
218
219
220     /* And make sure our hooks don't change the behaviour. */
221
222     /* execve(2) */
223     if (!skip--) {
224         printf("\nCHECKING TRANSPARENCY.\n\n");
225         fflush(stdout);
226
227         char *args[] = { argv0, NULL };
228         char *envp[] = { ldpreload, NULL };
229
230         execve(argv[0], args, envp);
231         return EXIT_FAILURE;
232     } else if (!skip--) {
233         char *args[] = { argv0, NULL };
234         char *envp[] = { "TEST=42", ldpreload, NULL };
235
236         execve(argv[0], args, envp);
237         return EXIT_FAILURE;
238     } else if (!skip--) {
239         char *args[] = { argv0, "foo", "bar", NULL };
240         char *envp[] = { "TEST=43", "FOO=", ldpreload, NULL };
241
242         execve(argv[0], args, envp);
243         return EXIT_FAILURE;
244
245     /* execl(3) */
246     } else if (!skip--) {
247         setenv("TEST", "44", 1);
248
249         execl(argv[0], argv0, NULL);
250         return EXIT_FAILURE;
251     } else if (!skip--) {
252         setenv("TEST", "45", 1);
253
254         execl(argv[0], argv0, "foo", "bar", NULL);
255         return EXIT_FAILURE;
256
257     /* execp(3), but not testing the p(ath) part */
258     } else if (!skip--) {
259         setenv("TEST", "46", 1);
260
261         execlp(argv[0], argv0, NULL);
262         return EXIT_FAILURE;
263     } else if (!skip--) {
264         setenv("TEST", "47", 1);
265
266         execlp(argv[0], argv0, "foo", "bar", NULL);
267         return EXIT_FAILURE;
268
269     /* execle(3) */
270     } else if (!skip--) {
271         char *envp[] = { ldpreload, NULL };
272
273         execle(argv[0], argv0, NULL, envp);
274         return EXIT_FAILURE;
275     } else if (!skip--) {
276         char *envp[] = { "TEST=48", ldpreload, NULL };
277
278         execle(argv[0], argv0, NULL, envp);
279         return EXIT_FAILURE;
280     } else if (!skip--) {
281         char *envp[] = { "TEST=49", "FOO=", ldpreload, NULL };
282
283         execle(argv[0], argv0, "foo", "bar", NULL, envp);
284         return EXIT_FAILURE;
285
286     /* execv(3) */
287     } else if (!skip--) {
288         setenv("TEST", "50", 1);
289
290         char *args[] = { argv0, NULL };
291
292         execv(argv[0], args);
293         return EXIT_FAILURE;
294     } else if (!skip--) {
295         setenv("TEST", "51", 1);
296
297         char *args[] = { argv0, "foo", "bar", NULL };
298
299         execv(argv[0], args);
300         return EXIT_FAILURE;
301
302     /* execvp(3), but not testing the p(ath) part */
303     } else if (!skip--) {
304         setenv("TEST", "52", 1);
305
306         char *args[] = { argv0, NULL };
307
308         execvp(argv[0], args);
309         return EXIT_FAILURE;
310     } else if (!skip--) {
311         setenv("TEST", "53", 1);
312
313         char *args[] = { argv0, "foo", "bar", NULL };
314
315         execvp(argv[0], args);
316         return EXIT_FAILURE;
317
318 #ifdef HAVE_EXECVPE
319     /* execvpe(3), but not testing the p(ath) part */
320     } else if (!skip--) {
321         char *args[] = { argv0, NULL };
322         char *envp[] = { "TEST=54", ldpreload, NULL };
323
324         execvpe(argv[0], args, envp);
325         return EXIT_FAILURE;
326     } else if (!skip--) {
327         char *args[] = { argv0, "foo", "bar", NULL };
328         char *envp[] = { "TEST=55", ldpreload, NULL };
329
330         execvpe(argv[0], args, envp);
331         return EXIT_FAILURE;
332 #else
333     /* Fake output to let the test pass. */
334     } else if (!skip--) {
335         puts("argv[0] = |./example_exec|");
336         puts("environ[0] = |COLORED_STDERR_PRIVATE_FDS=2,|");
337         puts("environ[1] = |TEST=54|");
338         puts("");
339         puts("argv[0] = |./example_exec|");
340         puts("argv[1] = |foo|");
341         puts("argv[2] = |bar|");
342         puts("environ[0] = |COLORED_STDERR_PRIVATE_FDS=2,|");
343         puts("environ[1] = |TEST=55|");
344         puts("");
345 #endif
346     }
347
348     printf("Done.\n");
349     return EXIT_SUCCESS;
350 }