1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
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/>.
23 #include <sys/prctl.h>
24 #include <sys/types.h>
28 #include "alloc-util.h"
29 #include "conf-files.h"
31 #include "exec-util.h"
36 #include "process-util.h"
38 #include "signal-util.h"
39 #include "stat-util.h"
40 #include "string-util.h"
42 #include "terminal-util.h"
45 /* Put this test here for a lack of better place */
46 assert_cc(EAGAIN == EWOULDBLOCK);
48 static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid) {
53 if (null_or_empty_path(path)) {
54 log_debug("%s is empty (a mask).", path);
58 r = safe_fork("(direxec)", FORK_DEATHSIG|FORK_LOG, &_pid);
65 r = rearrange_stdio(STDIN_FILENO, stdout_fd, STDERR_FILENO);
71 _argv[0] = (char*) path;
75 argv[0] = (char*) path;
78 log_error_errno(errno, "Failed to execute %s: %m", path);
86 static int do_execute(
89 gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
90 void* const callback_args[_STDOUT_CONSUME_MAX],
94 _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
95 _cleanup_strv_free_ char **paths = NULL;
99 /* We fork this all off from a child process so that we can somewhat cleanly make
100 * use of SIGALRM to set a time limit.
102 * If callbacks is nonnull, execution is serial. Otherwise, we default to parallel.
105 r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE, (const char* const*) directories);
110 pids = hashmap_new(NULL);
115 /* Abort execution of this process after the timout. We simply rely on SIGALRM as
116 * default action terminating the process, and turn on alarm(). */
118 if (timeout != USEC_INFINITY)
119 alarm(DIV_ROUND_UP(timeout, USEC_PER_SEC));
121 STRV_FOREACH(path, paths) {
122 _cleanup_free_ char *t = NULL;
123 _cleanup_close_ int fd = -1;
124 #if 0 /// No "maybe uninitialized" warning in elogind
135 fd = open_serialization_fd(basename(*path));
137 return log_error_errno(fd, "Failed to open serialization file: %m");
140 r = do_spawn(t, argv, fd, &pid);
145 r = hashmap_put(pids, PID_TO_PTR(pid), t);
150 r = wait_for_terminate_and_check(t, pid, WAIT_LOG);
154 if (lseek(fd, 0, SEEK_SET) < 0)
155 return log_error_errno(errno, "Failed to seek on serialization fd: %m");
157 r = callbacks[STDOUT_GENERATE](fd, callback_args[STDOUT_GENERATE]);
160 return log_error_errno(r, "Failed to process output from %s: %m", *path);
165 r = callbacks[STDOUT_COLLECT](output_fd, callback_args[STDOUT_COLLECT]);
167 return log_error_errno(r, "Callback two failed: %m");
170 while (!hashmap_isempty(pids)) {
171 _cleanup_free_ char *t = NULL;
174 pid = PTR_TO_PID(hashmap_first_key(pids));
177 t = hashmap_remove(pids, PID_TO_PTR(pid));
180 (void) wait_for_terminate_and_check(t, pid, WAIT_LOG);
186 int execute_directories(
187 const char* const* directories,
189 gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
190 void* const callback_args[_STDOUT_CONSUME_MAX],
193 char **dirs = (char**) directories;
194 _cleanup_close_ int fd = -1;
198 assert(!strv_isempty(dirs));
200 name = basename(dirs[0]);
201 assert(!isempty(name));
204 assert(callback_args);
205 assert(callbacks[STDOUT_GENERATE]);
206 assert(callbacks[STDOUT_COLLECT]);
207 assert(callbacks[STDOUT_CONSUME]);
209 fd = open_serialization_fd(name);
211 return log_error_errno(fd, "Failed to open serialization file: %m");
214 /* Executes all binaries in the directories serially or in parallel and waits for
215 * them to finish. Optionally a timeout is applied. If a file with the same name
216 * exists in more than one directory, the earliest one wins. */
218 r = safe_fork("(sd-executor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
222 r = do_execute(dirs, timeout, callbacks, callback_args, fd, argv);
223 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
229 if (lseek(fd, 0, SEEK_SET) < 0)
230 return log_error_errno(errno, "Failed to rewind serialization fd: %m");
232 r = callbacks[STDOUT_CONSUME](fd, callback_args[STDOUT_CONSUME]);
235 return log_error_errno(r, "Failed to parse returned data: %m");
239 #if 0 /// UNNEEDED by elogind
240 static int gather_environment_generate(int fd, void *arg) {
241 char ***env = arg, **x, **y;
242 _cleanup_fclose_ FILE *f = NULL;
243 _cleanup_strv_free_ char **new = NULL;
246 /* Read a series of VAR=value assignments from fd, use them to update the list of
247 * variables in env. Also update the exported environment.
249 * fd is always consumed, even on error.
260 r = load_env_file_pairs(f, NULL, NULL, &new);
264 STRV_FOREACH_PAIR(x, y, new) {
267 if (!env_name_is_valid(*x)) {
268 log_warning("Invalid variable assignment \"%s=...\", ignoring.", *x);
272 p = strjoin(*x, "=", *y);
276 r = strv_env_replace(env, p);
280 if (setenv(*x, *y, true) < 0)
287 static int gather_environment_collect(int fd, void *arg) {
289 _cleanup_fclose_ FILE *f = NULL;
292 /* Write out a series of env=cescape(VAR=value) assignments to fd. */
302 r = serialize_environment(f, *env);
307 return errno > 0 ? -errno : -EIO;
312 static int gather_environment_consume(int fd, void *arg) {
314 _cleanup_fclose_ FILE *f = NULL;
318 /* Read a series of env=cescape(VAR=value) assignments from fd into env. */
328 FOREACH_LINE(line, f, return -EIO) {
331 k = deserialize_environment(env, line);
333 log_error_errno(k, "Invalid line \"%s\": %m", line);
341 const gather_stdout_callback_t gather_environment[] = {
342 gather_environment_generate,
343 gather_environment_collect,
344 gather_environment_consume,