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 #if 0 /// UNNEEDED by elogind
276 static void test_environment_gathering(void) {
277 char template[] = "/tmp/test-exec-util.XXXXXXX", **p;
278 const char *dirs[] = {template, NULL};
279 const char *name, *name2, *name3;
282 char **tmp = NULL; /* this is only used in the forked process, no cleanup here */
283 _cleanup_strv_free_ char **env = NULL;
285 void* const args[] = { &tmp, &tmp, &env };
287 assert_se(mkdtemp(template));
289 log_info("/* %s */", __func__);
292 name = strjoina(template, "/10-foo");
293 name2 = strjoina(template, "/20-bar");
294 name3 = strjoina(template, "/30-last");
296 assert_se(write_string_file(name,
299 WRITE_STRING_FILE_CREATE) == 0);
300 assert_se(write_string_file(name2,
302 "echo A=22:$A\n\n\n", /* substitution from previous generator */
303 WRITE_STRING_FILE_CREATE) == 0);
304 assert_se(write_string_file(name3,
309 "echo C=001\n" /* variable overwriting */
310 /* various invalid entries */
317 /* test variable assignment without newline */
318 "echo PATH=$PATH:/no/such/file", /* no newline */
319 WRITE_STRING_FILE_CREATE) == 0);
321 assert_se(chmod(name, 0755) == 0);
322 assert_se(chmod(name2, 0755) == 0);
323 assert_se(chmod(name3, 0755) == 0);
325 r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL);
329 log_info("got env: \"%s\"", *p);
331 assert_se(streq(strv_env_get(env, "A"), "22:23:24"));
332 assert_se(streq(strv_env_get(env, "B"), "12"));
333 assert_se(streq(strv_env_get(env, "C"), "001"));
334 assert_se(endswith(strv_env_get(env, "PATH"), ":/no/such/file"));
338 int main(int argc, char *argv[]) {
339 log_set_max_level(LOG_DEBUG);
340 log_parse_environment();
343 test_execute_directory(true);
344 test_execute_directory(false);
345 test_execution_order();
346 test_stdout_gathering();
347 #if 0 /// UNNEEDED by elogind
348 test_environment_gathering();