2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
5 Copyright 2013 Thomas H.P. Andersen
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include "alloc-util.h"
31 #include "exec-util.h"
38 #include "string-util.h"
41 static int here
= 0, here2
= 0, here3
= 0;
42 void *ignore_stdout_args
[] = {&here
, &here2
, &here3
};
44 /* noop handlers, just check that arguments are passed correctly */
45 static int ignore_stdout_func(int fd
, void *arg
) {
52 static int ignore_stdout_func2(int fd
, void *arg
) {
54 assert(arg
== &here2
);
59 static int ignore_stdout_func3(int fd
, void *arg
) {
61 assert(arg
== &here3
);
67 static const gather_stdout_callback_t ignore_stdout
[] = {
73 static void test_execute_directory(bool gather_stdout
) {
74 char template_lo
[] = "/tmp/test-exec-util.XXXXXXX";
75 char template_hi
[] = "/tmp/test-exec-util.XXXXXXX";
76 const char * dirs
[] = {template_hi
, template_lo
, NULL
};
77 const char *name
, *name2
, *name3
, *overridden
, *override
, *masked
, *mask
;
79 log_info("/* %s (%s) */", __func__
, gather_stdout
? "gathering stdout" : "asynchronous");
81 assert_se(mkdtemp(template_lo
));
82 assert_se(mkdtemp(template_hi
));
84 name
= strjoina(template_lo
, "/script");
85 name2
= strjoina(template_hi
, "/script2");
86 name3
= strjoina(template_lo
, "/useless");
87 overridden
= strjoina(template_lo
, "/overridden");
88 override
= strjoina(template_hi
, "/overridden");
89 masked
= strjoina(template_lo
, "/masked");
90 mask
= strjoina(template_hi
, "/masked");
92 assert_se(write_string_file(name
,
93 "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works",
94 WRITE_STRING_FILE_CREATE
) == 0);
95 assert_se(write_string_file(name2
,
96 "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works2",
97 WRITE_STRING_FILE_CREATE
) == 0);
98 assert_se(write_string_file(overridden
,
99 "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed",
100 WRITE_STRING_FILE_CREATE
) == 0);
101 assert_se(write_string_file(override
,
102 "#!/bin/sh\necho 'Executing '$0",
103 WRITE_STRING_FILE_CREATE
) == 0);
104 assert_se(write_string_file(masked
,
105 "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed",
106 WRITE_STRING_FILE_CREATE
) == 0);
107 assert_se(symlink("/dev/null", mask
) == 0);
108 assert_se(touch(name3
) >= 0);
110 assert_se(chmod(name
, 0755) == 0);
111 assert_se(chmod(name2
, 0755) == 0);
112 assert_se(chmod(overridden
, 0755) == 0);
113 assert_se(chmod(override
, 0755) == 0);
114 assert_se(chmod(masked
, 0755) == 0);
117 execute_directories(dirs
, DEFAULT_TIMEOUT_USEC
, ignore_stdout
, ignore_stdout_args
, NULL
);
119 execute_directories(dirs
, DEFAULT_TIMEOUT_USEC
, NULL
, NULL
, NULL
);
121 assert_se(chdir(template_lo
) == 0);
122 assert_se(access("it_works", F_OK
) >= 0);
123 assert_se(access("failed", F_OK
) < 0);
125 assert_se(chdir(template_hi
) == 0);
126 assert_se(access("it_works2", F_OK
) >= 0);
127 assert_se(access("failed", F_OK
) < 0);
129 (void) rm_rf(template_lo
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
130 (void) rm_rf(template_hi
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
133 static void test_execution_order(void) {
134 char template_lo
[] = "/tmp/test-exec-util-lo.XXXXXXX";
135 char template_hi
[] = "/tmp/test-exec-util-hi.XXXXXXX";
136 const char *dirs
[] = {template_hi
, template_lo
, NULL
};
137 const char *name
, *name2
, *name3
, *overridden
, *override
, *masked
, *mask
;
138 const char *output
, *t
;
139 _cleanup_free_
char *contents
= NULL
;
141 assert_se(mkdtemp(template_lo
));
142 assert_se(mkdtemp(template_hi
));
144 output
= strjoina(template_hi
, "/output");
146 log_info("/* %s >>%s */", __func__
, output
);
148 /* write files in "random" order */
149 name2
= strjoina(template_lo
, "/90-bar");
150 name
= strjoina(template_hi
, "/80-foo");
151 name3
= strjoina(template_lo
, "/last");
152 overridden
= strjoina(template_lo
, "/30-override");
153 override
= strjoina(template_hi
, "/30-override");
154 masked
= strjoina(template_lo
, "/10-masked");
155 mask
= strjoina(template_hi
, "/10-masked");
157 t
= strjoina("#!/bin/sh\necho $(basename $0) >>", output
);
158 assert_se(write_string_file(name
, t
, WRITE_STRING_FILE_CREATE
) == 0);
160 t
= strjoina("#!/bin/sh\necho $(basename $0) >>", output
);
161 assert_se(write_string_file(name2
, t
, WRITE_STRING_FILE_CREATE
) == 0);
163 t
= strjoina("#!/bin/sh\necho $(basename $0) >>", output
);
164 assert_se(write_string_file(name3
, t
, WRITE_STRING_FILE_CREATE
) == 0);
166 t
= strjoina("#!/bin/sh\necho OVERRIDDEN >>", output
);
167 assert_se(write_string_file(overridden
, t
, WRITE_STRING_FILE_CREATE
) == 0);
169 t
= strjoina("#!/bin/sh\necho $(basename $0) >>", output
);
170 assert_se(write_string_file(override
, t
, WRITE_STRING_FILE_CREATE
) == 0);
172 t
= strjoina("#!/bin/sh\necho MASKED >>", output
);
173 assert_se(write_string_file(masked
, t
, WRITE_STRING_FILE_CREATE
) == 0);
175 assert_se(symlink("/dev/null", mask
) == 0);
177 assert_se(chmod(name
, 0755) == 0);
178 assert_se(chmod(name2
, 0755) == 0);
179 assert_se(chmod(name3
, 0755) == 0);
180 assert_se(chmod(overridden
, 0755) == 0);
181 assert_se(chmod(override
, 0755) == 0);
182 assert_se(chmod(masked
, 0755) == 0);
184 execute_directories(dirs
, DEFAULT_TIMEOUT_USEC
, ignore_stdout
, ignore_stdout_args
, NULL
);
186 assert_se(read_full_file(output
, &contents
, NULL
) >= 0);
187 assert_se(streq(contents
, "30-override\n80-foo\n90-bar\nlast\n"));
189 (void) rm_rf(template_lo
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
190 (void) rm_rf(template_hi
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
193 static int gather_stdout_one(int fd
, void *arg
) {
198 assert_se(read(fd
, buf
, sizeof buf
) >= 0);
201 assert_se(t
= strndup(buf
, sizeof buf
));
202 assert_se(strv_push(s
, t
) >= 0);
206 static int gather_stdout_two(int fd
, void *arg
) {
207 char ***s
= arg
, **t
;
210 assert_se(write(fd
, *t
, strlen(*t
)) == (ssize_t
) strlen(*t
));
215 static int gather_stdout_three(int fd
, void *arg
) {
219 assert_se(read(fd
, buf
, sizeof buf
- 1) > 0);
221 assert_se(*s
= strndup(buf
, sizeof buf
));
226 const gather_stdout_callback_t
const gather_stdout
[] = {
233 static void test_stdout_gathering(void) {
234 char template[] = "/tmp/test-exec-util.XXXXXXX";
235 const char *dirs
[] = {template, NULL
};
236 const char *name
, *name2
, *name3
;
239 char **tmp
= NULL
; /* this is only used in the forked process, no cleanup here */
240 _cleanup_free_
char *output
= NULL
;
242 void* args
[] = {&tmp
, &tmp
, &output
};
244 assert_se(mkdtemp(template));
246 log_info("/* %s */", __func__
);
249 name
= strjoina(template, "/10-foo");
250 name2
= strjoina(template, "/20-bar");
251 name3
= strjoina(template, "/30-last");
253 assert_se(write_string_file(name
,
254 "#!/bin/sh\necho a\necho b\necho c\n",
255 WRITE_STRING_FILE_CREATE
) == 0);
256 assert_se(write_string_file(name2
,
257 "#!/bin/sh\necho d\n",
258 WRITE_STRING_FILE_CREATE
) == 0);
259 assert_se(write_string_file(name3
,
260 "#!/bin/sh\nsleep 1",
261 WRITE_STRING_FILE_CREATE
) == 0);
263 assert_se(chmod(name
, 0755) == 0);
264 assert_se(chmod(name2
, 0755) == 0);
265 assert_se(chmod(name3
, 0755) == 0);
267 r
= execute_directories(dirs
, DEFAULT_TIMEOUT_USEC
, gather_stdout
, args
, NULL
);
270 log_info("got: %s", output
);
272 assert_se(streq(output
, "a\nb\nc\nd\n"));
275 static void test_environment_gathering(void) {
276 char template[] = "/tmp/test-exec-util.XXXXXXX", **p
;
277 const char *dirs
[] = {template, NULL
};
278 const char *name
, *name2
, *name3
;
281 char **tmp
= NULL
; /* this is only used in the forked process, no cleanup here */
282 _cleanup_strv_free_
char **env
= NULL
;
284 void* const args
[] = { &tmp
, &tmp
, &env
};
286 assert_se(mkdtemp(template));
288 log_info("/* %s */", __func__
);
291 name
= strjoina(template, "/10-foo");
292 name2
= strjoina(template, "/20-bar");
293 name3
= strjoina(template, "/30-last");
295 assert_se(write_string_file(name
,
298 WRITE_STRING_FILE_CREATE
) == 0);
299 assert_se(write_string_file(name2
,
301 "echo A=22:$A\n\n\n", /* substitution from previous generator */
302 WRITE_STRING_FILE_CREATE
) == 0);
303 assert_se(write_string_file(name3
,
308 "echo C=001\n" /* variable overwriting */
309 /* various invalid entries */
316 /* test variable assignment without newline */
317 "echo PATH=$PATH:/no/such/file", /* no newline */
318 WRITE_STRING_FILE_CREATE
) == 0);
320 assert_se(chmod(name
, 0755) == 0);
321 assert_se(chmod(name2
, 0755) == 0);
322 assert_se(chmod(name3
, 0755) == 0);
324 r
= execute_directories(dirs
, DEFAULT_TIMEOUT_USEC
, gather_environment
, args
, NULL
);
328 log_info("got env: \"%s\"", *p
);
330 assert_se(streq(strv_env_get(env
, "A"), "22:23:24"));
331 assert_se(streq(strv_env_get(env
, "B"), "12"));
332 assert_se(streq(strv_env_get(env
, "C"), "001"));
333 assert_se(endswith(strv_env_get(env
, "PATH"), ":/no/such/file"));
336 int main(int argc
, char *argv
[]) {
337 log_set_max_level(LOG_DEBUG
);
338 log_parse_environment();
341 test_execute_directory(true);
342 test_execute_directory(false);
343 test_execution_order();
344 test_stdout_gathering();
345 test_environment_gathering();