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