2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/prctl.h>
23 #include <sys/types.h>
26 #include "alloc-util.h"
27 #include "conf-files.h"
28 #include "exec-util.h"
31 #include "process-util.h"
33 #include "signal-util.h"
34 #include "stat-util.h"
35 #include "string-util.h"
39 /* Put this test here for a lack of better place */
40 assert_cc(EAGAIN
== EWOULDBLOCK
);
42 static int do_spawn(const char *path
, char *argv
[], pid_t
*pid
) {
45 if (null_or_empty_path(path
)) {
46 log_debug("%s is empty (a mask).", path
);
52 return log_error_errno(errno
, "Failed to fork: %m");
56 assert_se(prctl(PR_SET_PDEATHSIG
, SIGTERM
) == 0);
59 _argv
[0] = (char*) path
;
63 argv
[0] = (char*) path
;
66 log_error_errno(errno
, "Failed to execute %s: %m", path
);
70 log_debug("Spawned %s as " PID_FMT
".", path
, _pid
);
75 static int do_execute(char **directories
, usec_t timeout
, char *argv
[]) {
76 _cleanup_hashmap_free_free_ Hashmap
*pids
= NULL
;
77 _cleanup_strv_free_
char **paths
= NULL
;
81 /* We fork this all off from a child process so that we can
82 * somewhat cleanly make use of SIGALRM to set a time limit */
84 (void) reset_all_signal_handlers();
85 (void) reset_signal_mask();
87 assert_se(prctl(PR_SET_PDEATHSIG
, SIGTERM
) == 0);
89 r
= conf_files_list_strv(&paths
, NULL
, NULL
, (const char* const*) directories
);
93 pids
= hashmap_new(NULL
);
97 STRV_FOREACH(path
, paths
) {
98 _cleanup_free_
char *t
= NULL
;
105 r
= do_spawn(t
, argv
, &pid
);
109 r
= hashmap_put(pids
, PID_TO_PTR(pid
), t
);
116 /* Abort execution of this process after the timout. We simply
117 * rely on SIGALRM as default action terminating the process,
118 * and turn on alarm(). */
120 if (timeout
!= USEC_INFINITY
)
121 alarm((timeout
+ USEC_PER_SEC
- 1) / USEC_PER_SEC
);
123 while (!hashmap_isempty(pids
)) {
124 _cleanup_free_
char *t
= NULL
;
127 pid
= PTR_TO_PID(hashmap_first_key(pids
));
130 t
= hashmap_remove(pids
, PID_TO_PTR(pid
));
133 wait_for_terminate_and_warn(t
, pid
, true);
139 void execute_directories(const char* const* directories
, usec_t timeout
, char *argv
[]) {
143 char **dirs
= (char**) directories
;
145 assert(!strv_isempty(dirs
));
147 name
= basename(dirs
[0]);
148 assert(!isempty(name
));
150 /* Executes all binaries in the directories in parallel and waits
151 * for them to finish. Optionally a timeout is applied. If a file
152 * with the same name exists in more than one directory, the
153 * earliest one wins. */
155 executor_pid
= fork();
156 if (executor_pid
< 0) {
157 log_error_errno(errno
, "Failed to fork: %m");
160 } else if (executor_pid
== 0) {
161 r
= do_execute(dirs
, timeout
, argv
);
162 _exit(r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
);
165 wait_for_terminate_and_warn(name
, executor_pid
, true);