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"
30 #include "exec-util.h"
37 #include "string-util.h"
40 static int here
= 0, here2
= 0, here3
= 0;
41 void *ignore_stdout_args
[] = {&here
, &here2
, &here3
};
43 /* noop handlers, just check that arguments are passed correctly */
44 static int ignore_stdout_func(int fd
, void *arg
) {
51 static int ignore_stdout_func2(int fd
, void *arg
) {
53 assert(arg
== &here2
);
58 static int ignore_stdout_func3(int fd
, void *arg
) {
60 assert(arg
== &here3
);
66 static const gather_stdout_callback_t ignore_stdout
[] = {
72 static void test_execute_directory(bool gather_stdout
) {
73 char template_lo
[] = "/tmp/test-exec-util.XXXXXXX";
74 char template_hi
[] = "/tmp/test-exec-util.XXXXXXX";
75 const char * dirs
[] = {template_hi
, template_lo
, NULL
};
76 const char *name
, *name2
, *name3
, *overridden
, *override
, *masked
, *mask
;
78 log_info("/* %s (%s) */", __func__
, gather_stdout
? "gathering stdout" : "asynchronous");
80 assert_se(mkdtemp(template_lo
));
81 assert_se(mkdtemp(template_hi
));
83 name
= strjoina(template_lo
, "/script");
84 name2
= strjoina(template_hi
, "/script2");
85 name3
= strjoina(template_lo
, "/useless");
86 overridden
= strjoina(template_lo
, "/overridden");
87 override
= strjoina(template_hi
, "/overridden");
88 masked
= strjoina(template_lo
, "/masked");
89 mask
= strjoina(template_hi
, "/masked");
91 assert_se(write_string_file(name
,
92 "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works",
93 WRITE_STRING_FILE_CREATE
) == 0);
94 assert_se(write_string_file(name2
,
95 "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works2",
96 WRITE_STRING_FILE_CREATE
) == 0);
97 assert_se(write_string_file(overridden
,
98 "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed",
99 WRITE_STRING_FILE_CREATE
) == 0);
100 assert_se(write_string_file(override
,
101 "#!/bin/sh\necho 'Executing '$0",
102 WRITE_STRING_FILE_CREATE
) == 0);
103 assert_se(write_string_file(masked
,
104 "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed",
105 WRITE_STRING_FILE_CREATE
) == 0);
106 assert_se(symlink("/dev/null", mask
) == 0);
107 assert_se(touch(name3
) >= 0);
109 assert_se(chmod(name
, 0755) == 0);
110 assert_se(chmod(name2
, 0755) == 0);
111 assert_se(chmod(overridden
, 0755) == 0);
112 assert_se(chmod(override
, 0755) == 0);
113 assert_se(chmod(masked
, 0755) == 0);
116 execute_directories(dirs
, DEFAULT_TIMEOUT_USEC
, ignore_stdout
, ignore_stdout_args
, NULL
);
118 execute_directories(dirs
, DEFAULT_TIMEOUT_USEC
, NULL
, NULL
, NULL
);
120 assert_se(chdir(template_lo
) == 0);
121 assert_se(access("it_works", F_OK
) >= 0);
122 assert_se(access("failed", F_OK
) < 0);
124 assert_se(chdir(template_hi
) == 0);
125 assert_se(access("it_works2", F_OK
) >= 0);
126 assert_se(access("failed", F_OK
) < 0);
128 (void) rm_rf(template_lo
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
129 (void) rm_rf(template_hi
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
132 static void test_execution_order(void) {
133 char template_lo
[] = "/tmp/test-exec-util-lo.XXXXXXX";
134 char template_hi
[] = "/tmp/test-exec-util-hi.XXXXXXX";
135 const char *dirs
[] = {template_hi
, template_lo
, NULL
};
136 const char *name
, *name2
, *name3
, *overridden
, *override
, *masked
, *mask
;
137 const char *output
, *t
;
138 _cleanup_free_
char *contents
= NULL
;
140 assert_se(mkdtemp(template_lo
));
141 assert_se(mkdtemp(template_hi
));
143 output
= strjoina(template_hi
, "/output");
145 log_info("/* %s >>%s */", __func__
, output
);
147 /* write files in "random" order */
148 name2
= strjoina(template_lo
, "/90-bar");
149 name
= strjoina(template_hi
, "/80-foo");
150 name3
= strjoina(template_lo
, "/last");
151 overridden
= strjoina(template_lo
, "/30-override");
152 override
= strjoina(template_hi
, "/30-override");
153 masked
= strjoina(template_lo
, "/10-masked");
154 mask
= strjoina(template_hi
, "/10-masked");
156 t
= strjoina("#!/bin/sh\necho $(basename $0) >>", output
);
157 assert_se(write_string_file(name
, t
, WRITE_STRING_FILE_CREATE
) == 0);
159 t
= strjoina("#!/bin/sh\necho $(basename $0) >>", output
);
160 assert_se(write_string_file(name2
, t
, WRITE_STRING_FILE_CREATE
) == 0);
162 t
= strjoina("#!/bin/sh\necho $(basename $0) >>", output
);
163 assert_se(write_string_file(name3
, t
, WRITE_STRING_FILE_CREATE
) == 0);
165 t
= strjoina("#!/bin/sh\necho OVERRIDDEN >>", output
);
166 assert_se(write_string_file(overridden
, t
, WRITE_STRING_FILE_CREATE
) == 0);
168 t
= strjoina("#!/bin/sh\necho $(basename $0) >>", output
);
169 assert_se(write_string_file(override
, t
, WRITE_STRING_FILE_CREATE
) == 0);
171 t
= strjoina("#!/bin/sh\necho MASKED >>", output
);
172 assert_se(write_string_file(masked
, t
, WRITE_STRING_FILE_CREATE
) == 0);
174 assert_se(symlink("/dev/null", mask
) == 0);
176 assert_se(chmod(name
, 0755) == 0);
177 assert_se(chmod(name2
, 0755) == 0);
178 assert_se(chmod(name3
, 0755) == 0);
179 assert_se(chmod(overridden
, 0755) == 0);
180 assert_se(chmod(override
, 0755) == 0);
181 assert_se(chmod(masked
, 0755) == 0);
183 execute_directories(dirs
, DEFAULT_TIMEOUT_USEC
, ignore_stdout
, ignore_stdout_args
, NULL
);
185 assert_se(read_full_file(output
, &contents
, NULL
) >= 0);
186 assert_se(streq(contents
, "30-override\n80-foo\n90-bar\nlast\n"));
188 (void) rm_rf(template_lo
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
189 (void) rm_rf(template_hi
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
192 static int gather_stdout_one(int fd
, void *arg
) {
197 assert_se(read(fd
, buf
, sizeof buf
) >= 0);
200 assert_se(t
= strndup(buf
, sizeof buf
));
201 assert_se(strv_push(s
, t
) >= 0);
205 static int gather_stdout_two(int fd
, void *arg
) {
206 char ***s
= arg
, **t
;
209 assert_se(write(fd
, *t
, strlen(*t
)) == (ssize_t
) strlen(*t
));
214 static int gather_stdout_three(int fd
, void *arg
) {
218 assert_se(read(fd
, buf
, sizeof buf
- 1) > 0);
220 assert_se(*s
= strndup(buf
, sizeof buf
));
225 const gather_stdout_callback_t
const gather_stdout
[] = {
232 static void test_stdout_gathering(void) {
233 char template[] = "/tmp/test-exec-util.XXXXXXX";
234 const char *dirs
[] = {template, NULL
};
235 const char *name
, *name2
, *name3
;
238 char **tmp
= NULL
; /* this is only used in the forked process, no cleanup here */
239 _cleanup_free_
char *output
= NULL
;
241 void* args
[] = {&tmp
, &tmp
, &output
};
243 assert_se(mkdtemp(template));
245 log_info("/* %s */", __func__
);
248 name
= strjoina(template, "/10-foo");
249 name2
= strjoina(template, "/20-bar");
250 name3
= strjoina(template, "/30-last");
252 assert_se(write_string_file(name
,
253 "#!/bin/sh\necho a\necho b\necho c\n",
254 WRITE_STRING_FILE_CREATE
) == 0);
255 assert_se(write_string_file(name2
,
256 "#!/bin/sh\necho d\n",
257 WRITE_STRING_FILE_CREATE
) == 0);
258 assert_se(write_string_file(name3
,
259 "#!/bin/sh\nsleep 1",
260 WRITE_STRING_FILE_CREATE
) == 0);
262 assert_se(chmod(name
, 0755) == 0);
263 assert_se(chmod(name2
, 0755) == 0);
264 assert_se(chmod(name3
, 0755) == 0);
266 r
= execute_directories(dirs
, DEFAULT_TIMEOUT_USEC
, gather_stdout
, args
, NULL
);
269 log_info("got: %s", output
);
271 assert_se(streq(output
, "a\nb\nc\nd\n"));
274 int main(int argc
, char *argv
[]) {
275 log_set_max_level(LOG_DEBUG
);
276 log_parse_environment();
279 test_execute_directory(true);
280 test_execute_directory(false);
281 test_execution_order();
282 test_stdout_gathering();