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