]> ruderich.org/simon Gitweb - coloredstderr/coloredstderr.git/blob - tests/example_exec.c
2d22ce029fbcd56a267ca1a9d976d23dbfe5ae7e
[coloredstderr/coloredstderr.git] / tests / example_exec.c
1 /*
2  * Test execve() and exec*() functions.
3  *
4  * Copyright (C) 2013  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 "../src/compiler.h"
31
32
33 #define MAGIC "@RUN_"
34 #define MAGIC_LENGTH (strlen(MAGIC))
35
36 #define SETUP_RUN(number) \
37         sprintf(argv0, "%s" MAGIC "%03d", argv[0], (number))
38
39
40 extern char **environ;
41
42
43 static int find_magic_run_number(char *argv0, int *number) {
44     size_t length = strlen(argv0);
45     if (length <= MAGIC_LENGTH + 3) {
46         return 0;
47     }
48     /* Check if the string ends with "@RUN_YYY" where YYY should be a number
49      * (not checked). */
50     argv0 += length - MAGIC_LENGTH - 3;
51     if (strncmp(argv0, MAGIC, MAGIC_LENGTH)) {
52         return 0;
53     }
54     *number = atoi(argv0 + MAGIC_LENGTH);
55
56     /* Strip off "@RUN_YYY". */
57     argv0[0] = 0;
58     return 1;
59 }
60
61 static void dump(char *argv[]) {
62     size_t i;
63
64     i = 0;
65     while (*argv) {
66         printf("argv[%zu] = |%s|\n", i++, *argv++);
67     }
68     i = 0;
69     char **env = environ;
70     while (*env) {
71         /* Skip LD_PRELOAD which contains system dependent values. */
72         if (strncmp(*env, "LD_PRELOAD=", 11)) {
73             printf("environ[%zu] = |%s|\n", i, *env);
74         }
75         i++;
76         env++;
77     }
78     printf("\n");
79     /* When not writing to stdout (e.g. redirection while testing), glibc is
80      * buffering heavily. Flush to display the output before the exec*(). */
81     fflush(stdout);
82 }
83
84
85 int main(int argc unused, char **argv) {
86     char argv0[strlen(argv[0]) + MAGIC_LENGTH + 3 + 1];
87
88     char *old_ldpreload = getenv("LD_PRELOAD");
89     size_t ldpreload_length = strlen("LD_PRELOAD=") + 1;
90     if (old_ldpreload) {
91         ldpreload_length += strlen(old_ldpreload);
92     }
93     char ldpreload[ldpreload_length];
94     strcpy(ldpreload, "LD_PRELOAD=");
95     if (old_ldpreload) {
96         strcat(ldpreload, old_ldpreload);
97     }
98
99     int run;
100
101     /* First call. */
102     if (!find_magic_run_number(argv[0], &run)) {
103         SETUP_RUN(1);
104
105         char *args[] = { argv0, NULL };
106         char *envp[] = { ldpreload, NULL };
107
108         execve(argv[0], args, envp);
109         return EXIT_FAILURE;
110     }
111
112     /* Following calls, each testing an exec*() feature. */
113
114     dump(argv);
115     SETUP_RUN(run + 1);
116
117     int skip = run - 1;
118
119
120     /* Check that we update/insert the environment correctly. */
121
122     if (!skip--) {
123         printf("\nCHECKING COLORING.\n\n");
124         fflush(stdout);
125
126         dup2(2, 3);
127
128         char *args[] = { argv0, NULL };
129         char *envp[] = { ldpreload, NULL };
130
131         execve(argv[0], args, envp);
132         return EXIT_FAILURE;
133     } else if (!skip--) {
134         dup2(2, 4);
135
136         execl(argv[0], argv0, NULL);
137         return EXIT_FAILURE;
138     } else if (!skip--) {
139         dup2(2, 5);
140
141         execlp(argv[0], argv0, NULL);
142         return EXIT_FAILURE;
143     } else if (!skip--) {
144         dup2(2, 6);
145
146         char *envp[] = { ldpreload, NULL };
147
148         execle(argv[0], argv0, NULL, envp);
149         return EXIT_FAILURE;
150     } else if (!skip--) {
151         dup2(2, 7);
152
153         /* Test closing a few descriptors. */
154         close(5);
155         close(6);
156
157         char *args[] = { argv0, NULL };
158
159         execv(argv[0], args);
160         return EXIT_FAILURE;
161     } else if (!skip--) {
162         dup2(2, 8);
163
164         /* And a few more. */
165         close(7);
166         close(4);
167
168         char *args[] = { argv0, NULL };
169
170         execvp(argv[0], args);
171         return EXIT_FAILURE;
172
173     /* Test handling of COLORED_STDERR_FDS. */
174
175     } else if (!skip--) {
176         /* And the rest. */
177         close(3);
178         close(8);
179
180         dup2(2, 5);
181
182         char *args[] = { argv0, NULL };
183         char *envp[] = { ldpreload, "COLORED_STDERR_FDS=5,", NULL };
184
185         execve(argv[0], args, envp);
186         return EXIT_FAILURE;
187     } else if (!skip--) {
188         char *args[] = { argv0, NULL };
189         char *envp[] = { ldpreload, NULL };
190
191         dup2(5, 6);
192         close(5);
193
194         execve(argv[0], args, envp);
195         return EXIT_FAILURE;
196     } else if (!skip--) {
197         close(6);
198
199         char *args[] = { argv0, NULL };
200         setenv("COLORED_STDERR_FDS", "2,", 1);
201
202         execv(argv[0], args);
203         return EXIT_FAILURE;
204     }
205
206
207     /* And make sure our hooks don't change the behaviour. */
208
209     /* execve(2) */
210     if (!skip--) {
211         printf("\nCHECKING TRANSPARENCY.\n\n");
212         fflush(stdout);
213
214         char *args[] = { argv0, NULL };
215         char *envp[] = { ldpreload, NULL };
216
217         execve(argv[0], args, envp);
218         return EXIT_FAILURE;
219     } else if (!skip--) {
220         char *args[] = { argv0, NULL };
221         char *envp[] = { "TEST=42", ldpreload, NULL };
222
223         execve(argv[0], args, envp);
224         return EXIT_FAILURE;
225     } else if (!skip--) {
226         char *args[] = { argv0, "foo", "bar", NULL };
227         char *envp[] = { "TEST=43", "FOO=", ldpreload, NULL };
228
229         execve(argv[0], args, envp);
230         return EXIT_FAILURE;
231
232     /* execl(3) */
233     } else if (!skip--) {
234         setenv("TEST", "44", 1);
235
236         execl(argv[0], argv0, NULL);
237         return EXIT_FAILURE;
238     } else if (!skip--) {
239         setenv("TEST", "45", 1);
240
241         execl(argv[0], argv0, "foo", "bar", NULL);
242         return EXIT_FAILURE;
243
244     /* execp(3), but not testing the p(ath) part */
245     } else if (!skip--) {
246         setenv("TEST", "46", 1);
247
248         execlp(argv[0], argv0, NULL);
249         return EXIT_FAILURE;
250     } else if (!skip--) {
251         setenv("TEST", "47", 1);
252
253         execlp(argv[0], argv0, "foo", "bar", NULL);
254         return EXIT_FAILURE;
255
256     /* execle(3) */
257     } else if (!skip--) {
258         char *envp[] = { ldpreload, NULL };
259
260         execle(argv[0], argv0, NULL, envp);
261         return EXIT_FAILURE;
262     } else if (!skip--) {
263         char *envp[] = { "TEST=48", ldpreload, NULL };
264
265         execle(argv[0], argv0, NULL, envp);
266         return EXIT_FAILURE;
267     } else if (!skip--) {
268         char *envp[] = { "TEST=49", "FOO=", ldpreload, NULL };
269
270         execle(argv[0], argv0, "foo", "bar", NULL, envp);
271         return EXIT_FAILURE;
272
273     /* execv(3) */
274     } else if (!skip--) {
275         setenv("TEST", "50", 1);
276
277         char *args[] = { argv0, NULL };
278
279         execv(argv[0], args);
280         return EXIT_FAILURE;
281     } else if (!skip--) {
282         setenv("TEST", "51", 1);
283
284         char *args[] = { argv0, "foo", "bar", NULL };
285
286         execv(argv[0], args);
287         return EXIT_FAILURE;
288
289     /* execvp(3), but not testing the p(ath) part */
290     } else if (!skip--) {
291         setenv("TEST", "52", 1);
292
293         char *args[] = { argv0, NULL };
294
295         execvp(argv[0], args);
296         return EXIT_FAILURE;
297     } else if (!skip--) {
298         setenv("TEST", "53", 1);
299
300         char *args[] = { argv0, "foo", "bar", NULL };
301
302         execvp(argv[0], args);
303         return EXIT_FAILURE;
304
305 #ifdef HAVE_EXECVPE
306     /* execvpe(3), but not testing the p(ath) part */
307     } else if (!skip--) {
308         char *args[] = { argv0, NULL };
309         char *envp[] = { "TEST=54", ldpreload, NULL };
310
311         execvpe(argv[0], args, envp);
312         return EXIT_FAILURE;
313     } else if (!skip--) {
314         char *args[] = { argv0, "foo", "bar", NULL };
315         char *envp[] = { "TEST=55", ldpreload, NULL };
316
317         execvpe(argv[0], args, envp);
318         return EXIT_FAILURE;
319 #else
320     /* Fake output to let the test pass. */
321     } else if (!skip--) {
322         puts("argv[0] = |./example_exec|");
323         puts("environ[0] = |TEST=54|");
324         puts("environ[2] = |COLORED_STDERR_PRIVATE_FDS=2,|");
325         puts("");
326         puts("argv[0] = |./example_exec|");
327         puts("argv[1] = |foo|");
328         puts("argv[2] = |bar|");
329         puts("environ[0] = |TEST=55|");
330         puts("environ[2] = |COLORED_STDERR_PRIVATE_FDS=2,|");
331         puts("");
332 #endif
333     }
334
335     printf("Done.\n");
336     return EXIT_SUCCESS;
337 }