summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO6
-rw-r--r--src/basic/log.c98
-rw-r--r--src/basic/log.h1
-rw-r--r--src/core/execute.c315
4 files changed, 182 insertions, 238 deletions
diff --git a/TODO b/TODO
index b638ab95c8..dacce6cee0 100644
--- a/TODO
+++ b/TODO
@@ -26,12 +26,6 @@ Features:
* replace all uses of fgets() + LINE_MAX by read_line()
-* fix logging in execute.c: extend log.c to have an optional mode where
- log_open() is implicitly done before each log line and log_close() right
- after. This way we don't have open fds around but logs will still
- work. Because it is slow this mode should used exclusively in the execute.c
- case.
-
* set IPAddressDeny=any on all services that shouldn't do networking (possibly
combined with IPAddressAllow=localhost).
diff --git a/src/basic/log.c b/src/basic/log.c
index 168c6c37ce..4f0fe54579 100644
--- a/src/basic/log.c
+++ b/src/basic/log.c
@@ -74,6 +74,7 @@ static bool show_location = false;
static bool upgrade_syslog_to_journal = false;
static bool always_reopen_console = false;
+static bool open_when_needed = false;
/* Akin to glibc's __abort_msg; which is private and we hence cannot
* use here. */
@@ -585,6 +586,9 @@ int log_dispatch_internal(
if ((level & LOG_FACMASK) == 0)
level = log_facility | LOG_PRI(level);
+ if (open_when_needed)
+ log_open();
+
do {
char *e;
int k = 0;
@@ -640,6 +644,9 @@ int log_dispatch_internal(
buffer = e;
} while (buffer);
+ if (open_when_needed)
+ log_close();
+
return -error;
}
@@ -834,9 +841,8 @@ void log_assert_failed_return_realm(
}
int log_oom_internal(LogRealm realm, const char *file, int line, const char *func) {
- log_internal_realm(LOG_REALM_PLUS_LEVEL(realm, LOG_ERR),
- ENOMEM, file, line, func, "Out of memory.");
- return -ENOMEM;
+ return log_internal_realm(LOG_REALM_PLUS_LEVEL(realm, LOG_ERR),
+ ENOMEM, file, line, func, "Out of memory.");
}
int log_format_iovec(
@@ -911,38 +917,48 @@ int log_struct_internal(
if ((level & LOG_FACMASK) == 0)
level = log_facility | LOG_PRI(level);
- if (IN_SET(log_target, LOG_TARGET_AUTO,
- LOG_TARGET_JOURNAL_OR_KMSG,
- LOG_TARGET_JOURNAL) &&
- journal_fd >= 0) {
- char header[LINE_MAX];
- struct iovec iovec[17] = {};
- unsigned n = 0, i;
- int r;
- struct msghdr mh = {
- .msg_iov = iovec,
- };
- bool fallback = false;
-
- /* If the journal is available do structured logging */
- log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
- iovec[n++] = IOVEC_MAKE_STRING(header);
+ if (IN_SET(log_target,
+ LOG_TARGET_AUTO,
+ LOG_TARGET_JOURNAL_OR_KMSG,
+ LOG_TARGET_JOURNAL)) {
+
+ if (open_when_needed)
+ log_open_journal();
+
+ if (journal_fd >= 0) {
+ char header[LINE_MAX];
+ struct iovec iovec[17] = {};
+ unsigned n = 0, i;
+ int r;
+ struct msghdr mh = {
+ .msg_iov = iovec,
+ };
+ bool fallback = false;
+
+ /* If the journal is available do structured logging */
+ log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
+ iovec[n++] = IOVEC_MAKE_STRING(header);
+
+ va_start(ap, format);
+ r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, true, error, format, ap);
+ if (r < 0)
+ fallback = true;
+ else {
+ mh.msg_iovlen = n;
+ (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
+ }
- va_start(ap, format);
- r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, true, error, format, ap);
- if (r < 0)
- fallback = true;
- else {
- mh.msg_iovlen = n;
- (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
- }
+ va_end(ap);
+ for (i = 1; i < n; i += 2)
+ free(iovec[i].iov_base);
- va_end(ap);
- for (i = 1; i < n; i += 2)
- free(iovec[i].iov_base);
+ if (!fallback) {
+ if (open_when_needed)
+ log_close();
- if (!fallback)
- return -error;
+ return -error;
+ }
+ }
}
/* Fallback if journal logging is not available or didn't work. */
@@ -969,8 +985,12 @@ int log_struct_internal(
}
va_end(ap);
- if (!found)
+ if (!found) {
+ if (open_when_needed)
+ log_close();
+
return -error;
+ }
return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buf + 8);
}
@@ -1221,10 +1241,6 @@ void log_received_signal(int level, const struct signalfd_siginfo *si) {
}
-void log_set_upgrade_syslog_to_journal(bool b) {
- upgrade_syslog_to_journal = b;
-}
-
int log_syntax_internal(
const char *unit,
int level,
@@ -1272,6 +1288,14 @@ int log_syntax_internal(
NULL);
}
+void log_set_upgrade_syslog_to_journal(bool b) {
+ upgrade_syslog_to_journal = b;
+}
+
void log_set_always_reopen_console(bool b) {
always_reopen_console = b;
}
+
+void log_set_open_when_needed(bool b) {
+ open_when_needed = b;
+}
diff --git a/src/basic/log.h b/src/basic/log.h
index e3fd3203d0..10a6032788 100644
--- a/src/basic/log.h
+++ b/src/basic/log.h
@@ -303,6 +303,7 @@ void log_received_signal(int level, const struct signalfd_siginfo *si);
void log_set_upgrade_syslog_to_journal(bool b);
void log_set_always_reopen_console(bool b);
+void log_set_open_when_needed(bool b);
int log_syntax_internal(
const char *unit,
diff --git a/src/core/execute.c b/src/core/execute.c
index 0b49be2000..cd4b9f8eb2 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -588,7 +588,7 @@ static int setup_output(
case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
r = connect_logger_as(unit, context, params, o, ident, fileno, uid, gid);
if (r < 0) {
- log_unit_error_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr");
+ log_unit_warning_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr");
r = open_null_as(O_WRONLY, fileno);
} else {
struct stat st;
@@ -1323,9 +1323,7 @@ static bool skip_seccomp_unavailable(const Unit* u, const char* msg) {
if (is_seccomp_available())
return false;
- log_open();
log_unit_debug(u, "SECCOMP features not detected in the kernel, skipping %s", msg);
- log_close();
return true;
}
@@ -2109,10 +2107,8 @@ static int apply_mount_namespace(
/* If we couldn't set up the namespace this is probably due to a
* missing capability. In this case, silently proceeed. */
if (IN_SET(r, -EPERM, -EACCES)) {
- log_open();
log_unit_debug_errno(u, r, "Failed to set up namespace, assuming containerized execution, ignoring: %m");
- log_close();
- r = 0;
+ return 0;
}
return r;
@@ -2192,13 +2188,13 @@ static int setup_keyring(
keyring = keyctl(KEYCTL_JOIN_SESSION_KEYRING, 0, 0, 0, 0);
if (keyring == -1) {
if (errno == ENOSYS)
- log_debug_errno(errno, "Kernel keyring not supported, ignoring.");
+ log_unit_debug_errno(u, errno, "Kernel keyring not supported, ignoring.");
else if (IN_SET(errno, EACCES, EPERM))
- log_debug_errno(errno, "Kernel keyring access prohibited, ignoring.");
+ log_unit_debug_errno(u, errno, "Kernel keyring access prohibited, ignoring.");
else if (errno == EDQUOT)
- log_debug_errno(errno, "Out of kernel keyrings to allocate, ignoring.");
+ log_unit_debug_errno(u, errno, "Out of kernel keyrings to allocate, ignoring.");
else
- return log_error_errno(errno, "Setting up kernel keyring failed: %m");
+ return log_unit_error_errno(u, errno, "Setting up kernel keyring failed: %m");
return 0;
}
@@ -2209,19 +2205,19 @@ static int setup_keyring(
key = add_key("user", "invocation_id", &u->invocation_id, sizeof(u->invocation_id), KEY_SPEC_SESSION_KEYRING);
if (key == -1)
- log_debug_errno(errno, "Failed to add invocation ID to keyring, ignoring: %m");
+ log_unit_debug_errno(u, errno, "Failed to add invocation ID to keyring, ignoring: %m");
else {
if (keyctl(KEYCTL_SETPERM, key,
KEY_POS_VIEW|KEY_POS_READ|KEY_POS_SEARCH|
KEY_USR_VIEW|KEY_USR_READ|KEY_USR_SEARCH, 0, 0) < 0)
- return log_error_errno(errno, "Failed to restrict invocation ID permission: %m");
+ return log_unit_error_errno(u, errno, "Failed to restrict invocation ID permission: %m");
}
}
/* And now, make the keyring owned by the service's user */
if (uid_is_valid(uid) || gid_is_valid(gid))
if (keyctl(KEYCTL_CHOWN, keyring, uid, gid, 0) < 0)
- return log_error_errno(errno, "Failed to change ownership of session keyring: %m");
+ return log_unit_error_errno(u, errno, "Failed to change ownership of session keyring: %m");
/* When requested link the user keyring into the session keyring. */
if (context->keyring_mode == EXEC_KEYRING_SHARED) {
@@ -2237,13 +2233,13 @@ static int setup_keyring(
if (gid_is_valid(gid) && gid != saved_gid) {
if (setregid(gid, -1) < 0)
- return log_error_errno(errno, "Failed to change GID for user keyring: %m");
+ return log_unit_error_errno(u, errno, "Failed to change GID for user keyring: %m");
}
if (uid_is_valid(uid) && uid != saved_uid) {
if (setreuid(uid, -1) < 0) {
(void) setregid(saved_gid, -1);
- return log_error_errno(errno, "Failed to change UID for user keyring: %m");
+ return log_unit_error_errno(u, errno, "Failed to change UID for user keyring: %m");
}
}
@@ -2256,19 +2252,19 @@ static int setup_keyring(
(void) setreuid(saved_uid, -1);
(void) setregid(saved_gid, -1);
- return log_error_errno(r, "Failed to link user keyring into session keyring: %m");
+ return log_unit_error_errno(u, r, "Failed to link user keyring into session keyring: %m");
}
if (uid_is_valid(uid) && uid != saved_uid) {
if (setreuid(saved_uid, -1) < 0) {
(void) setregid(saved_gid, -1);
- return log_error_errno(errno, "Failed to change UID back for user keyring: %m");
+ return log_unit_error_errno(u, errno, "Failed to change UID back for user keyring: %m");
}
}
if (gid_is_valid(gid) && gid != saved_gid) {
if (setregid(saved_gid, -1) < 0)
- return log_error_errno(errno, "Failed to change GID back for user keyring: %m");
+ return log_unit_error_errno(u, errno, "Failed to change GID back for user keyring: %m");
}
}
@@ -2403,8 +2399,7 @@ static int exec_child(
unsigned n_socket_fds,
char **files_env,
int user_lookup_fd,
- int *exit_status,
- char **error_message) {
+ int *exit_status) {
_cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **final_argv = NULL;
_cleanup_free_ char *mac_selinux_context_net = NULL, *home_buffer = NULL;
@@ -2438,9 +2433,6 @@ static int exec_child(
assert(context);
assert(params);
assert(exit_status);
- assert(error_message);
- /* We don't always set error_message, hence it must be initialized */
- assert(*error_message == NULL);
rename_process_from_path(command->path);
@@ -2458,33 +2450,34 @@ static int exec_child(
r = reset_signal_mask();
if (r < 0) {
*exit_status = EXIT_SIGNAL_MASK;
- *error_message = strdup("Failed to set process signal mask");
- /* If strdup fails, here and below, we will just print the generic error message. */
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set process signal mask: %m");
}
if (params->idle_pipe)
do_idle_pipe_dance(params->idle_pipe);
- /* Close sockets very early to make sure we don't
- * block init reexecution because it cannot bind its
- * sockets */
+ /* Close fds we don't need very early to make sure we don't block init reexecution because it cannot bind its
+ * sockets. Among the fds we close are the logging fds, and we want to keep them closed, so that we don't have
+ * any fds open we don't really want open during the transition. In order to make logging work, we switch the
+ * log subsystem into open_when_needed mode, so that it reopens the logs on every single log call. */
log_forget_fds();
+ log_set_open_when_needed(true);
+
+ /* In case anything used libc syslog(), close this here, too */
+ closelog();
n_fds = n_storage_fds + n_socket_fds;
r = close_remaining_fds(params, runtime, dcreds, user_lookup_fd, socket_fd, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_FDS;
- *error_message = strdup("Failed to close unwanted file descriptors");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to close unwanted file descriptors: %m");
}
if (!context->same_pgrp)
if (setsid() < 0) {
*exit_status = EXIT_SETSID;
- *error_message = strdup("Failed to create new process session");
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to create new process session: %m");
}
exec_context_tty_reset(context, params);
@@ -2496,7 +2489,7 @@ static int exec_child(
cmdline = exec_command_line(argv);
if (!cmdline) {
*exit_status = EXIT_MEMORY;
- return -ENOMEM;
+ return log_oom();
}
r = ask_for_confirmation(vc, unit, cmdline);
@@ -2506,7 +2499,7 @@ static int exec_child(
return 0;
}
*exit_status = EXIT_CONFIRM;
- *error_message = strdup("Execution cancelled by the user");
+ log_unit_error(unit, "Execution cancelled by the user");
return -ECANCELED;
}
}
@@ -2516,27 +2509,24 @@ static int exec_child(
/* Make sure we bypass our own NSS module for any NSS checks */
if (putenv((char*) "SYSTEMD_NSS_DYNAMIC_BYPASS=1") != 0) {
*exit_status = EXIT_USER;
- *error_message = strdup("Failed to update environment");
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to update environment: %m");
}
r = dynamic_creds_realize(dcreds, &uid, &gid);
if (r < 0) {
*exit_status = EXIT_USER;
- *error_message = strdup("Failed to update dynamic user credentials");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to update dynamic user credentials: %m");
}
if (!uid_is_valid(uid)) {
*exit_status = EXIT_USER;
- (void) asprintf(error_message, "UID validation failed for \""UID_FMT"\"", uid);
- /* If asprintf fails, here and below, we will just print the generic error message. */
+ log_unit_error(unit, "UID validation failed for \""UID_FMT"\"", uid);
return -ESRCH;
}
if (!gid_is_valid(gid)) {
*exit_status = EXIT_USER;
- (void) asprintf(error_message, "GID validation failed for \""GID_FMT"\"", gid);
+ log_unit_error(unit, "GID validation failed for \""GID_FMT"\"", gid);
return -ESRCH;
}
@@ -2547,15 +2537,13 @@ static int exec_child(
r = get_fixed_user(context, &username, &uid, &gid, &home, &shell);
if (r < 0) {
*exit_status = EXIT_USER;
- *error_message = strdup("Failed to determine user credentials");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to determine user credentials: %m");
}
r = get_fixed_group(context, &groupname, &gid);
if (r < 0) {
*exit_status = EXIT_GROUP;
- *error_message = strdup("Failed to determine group credentials");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to determine group credentials: %m");
}
}
@@ -2564,15 +2552,13 @@ static int exec_child(
&supplementary_gids, &ngids);
if (r < 0) {
*exit_status = EXIT_GROUP;
- *error_message = strdup("Failed to determine supplementary groups");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to determine supplementary groups: %m");
}
r = send_user_lookup(unit, user_lookup_fd, uid, gid);
if (r < 0) {
*exit_status = EXIT_USER;
- *error_message = strdup("Failed to send user credentials to PID1");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to send user credentials to PID1: %m");
}
user_lookup_fd = safe_close(user_lookup_fd);
@@ -2580,8 +2566,7 @@ static int exec_child(
r = acquire_home(context, uid, &home, &home_buffer);
if (r < 0) {
*exit_status = EXIT_CHDIR;
- *error_message = strdup("Failed to determine $HOME for user");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to determine $HOME for user: %m");
}
/* If a socket is connected to STDIN/STDOUT/STDERR, we
@@ -2592,30 +2577,26 @@ static int exec_child(
r = setup_input(context, params, socket_fd, named_iofds);
if (r < 0) {
*exit_status = EXIT_STDIN;
- *error_message = strdup("Failed to set up standard input");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up standard input: %m");
}
r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, named_iofds, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
if (r < 0) {
*exit_status = EXIT_STDOUT;
- *error_message = strdup("Failed to set up standard output");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up standard output: %m");
}
r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, named_iofds, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
if (r < 0) {
*exit_status = EXIT_STDERR;
- *error_message = strdup("Failed to set up standard error output");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up standard error output: %m");
}
if (params->cgroup_path) {
r = cg_attach_everywhere(params->cgroup_supported, params->cgroup_path, 0, NULL, NULL);
if (r < 0) {
*exit_status = EXIT_CGROUP;
- (void) asprintf(error_message, "Failed to attach to cgroup %s", params->cgroup_path);
- return r;
+ return log_unit_error_errno(unit, r, "Failed to attach to cgroup %s: %m", params->cgroup_path);
}
}
@@ -2629,22 +2610,18 @@ static int exec_child(
sprintf(t, "%i", context->oom_score_adjust);
r = write_string_file("/proc/self/oom_score_adj", t, 0);
- if (r == -EPERM || r == -EACCES) {
- log_open();
+ if (IN_SET(r, -EPERM, -EACCES))
log_unit_debug_errno(unit, r, "Failed to adjust OOM setting, assuming containerized execution, ignoring: %m");
- log_close();
- } else if (r < 0) {
+ else if (r < 0) {
*exit_status = EXIT_OOM_ADJUST;
- *error_message = strdup("Failed to adjust OOM setting");
- return -errno;
+ return log_unit_error_errno(unit, r, "Failed to adjust OOM setting: %m");
}
}
if (context->nice_set)
if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
*exit_status = EXIT_NICE;
- *error_message = strdup("Failed to set up process scheduling priority (nice level)");
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to set up process scheduling priority (nice level): %m");
}
if (context->cpu_sched_set) {
@@ -2659,38 +2636,33 @@ static int exec_child(
&param);
if (r < 0) {
*exit_status = EXIT_SETSCHEDULER;
- *error_message = strdup("Failed to set up CPU scheduling");
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to set up CPU scheduling: %m");
}
}
if (context->cpuset)
if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
*exit_status = EXIT_CPUAFFINITY;
- *error_message = strdup("Failed to set up CPU affinity");
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to set up CPU affinity: %m");
}
if (context->ioprio_set)
if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
*exit_status = EXIT_IOPRIO;
- *error_message = strdup("Failed to set up IO scheduling priority");
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to set up IO scheduling priority: %m");
}
if (context->timer_slack_nsec != NSEC_INFINITY)
if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
*exit_status = EXIT_TIMERSLACK;
- *error_message = strdup("Failed to set up timer slack");
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to set up timer slack: %m");
}
if (context->personality != PERSONALITY_INVALID) {
r = safe_personality(context->personality);
if (r < 0) {
*exit_status = EXIT_PERSONALITY;
- *error_message = strdup("Failed to set up execution domain (personality)");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up execution domain (personality): %m");
}
}
@@ -2706,8 +2678,7 @@ static int exec_child(
r = chown_terminal(STDIN_FILENO, uid);
if (r < 0) {
*exit_status = EXIT_STDIN;
- *error_message = strdup("Failed to change ownership of terminal");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to change ownership of terminal: %m");
}
}
@@ -2718,25 +2689,20 @@ static int exec_child(
r = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0644, uid, gid);
if (r < 0) {
*exit_status = EXIT_CGROUP;
- *error_message = strdup("Failed to adjust control group access");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to adjust control group access: %m");
}
-
r = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0755, uid, gid);
if (r < 0) {
*exit_status = EXIT_CGROUP;
- *error_message = strdup("Failed to adjust control group access");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to adjust control group access: %m");
}
}
for (dt = 0; dt < _EXEC_DIRECTORY_MAX; dt++) {
r = setup_exec_directory(context, params, uid, gid, dt, exit_status);
- if (r < 0) {
- *error_message = strdup("Failed to set up special execution directory");
- return r;
- }
+ if (r < 0)
+ return log_unit_error_errno(unit, r, "Failed to set up special execution directory in %s: %m", params->prefix[dt]);
}
r = build_environment(
@@ -2752,13 +2718,13 @@ static int exec_child(
&our_env);
if (r < 0) {
*exit_status = EXIT_MEMORY;
- return r;
+ return log_oom();
}
r = build_pass_environment(context, &pass_env);
if (r < 0) {
*exit_status = EXIT_MEMORY;
- return r;
+ return log_oom();
}
accum_env = strv_env_merge(5,
@@ -2770,7 +2736,7 @@ static int exec_child(
NULL);
if (!accum_env) {
*exit_status = EXIT_MEMORY;
- return -ENOMEM;
+ return log_oom();
}
accum_env = strv_env_clean(accum_env);
@@ -2779,8 +2745,7 @@ static int exec_child(
r = setup_keyring(unit, context, params, uid, gid);
if (r < 0) {
*exit_status = EXIT_KEYRING;
- *error_message = strdup("Failed to set up kernel keyring");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up kernel keyring: %m");
}
/* We need sandboxing if the caller asked us to apply it and the command isn't explicitly excepted from it */
@@ -2816,8 +2781,7 @@ static int exec_child(
r = setup_pam(context->pam_name, username, uid, gid, context->tty_path, &accum_env, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_PAM;
- *error_message = strdup("Failed to set up PAM session");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up PAM session: %m");
}
}
}
@@ -2826,8 +2790,7 @@ static int exec_child(
r = setup_netns(runtime->netns_storage_socket);
if (r < 0) {
*exit_status = EXIT_NETWORK;
- *error_message = strdup("Failed to set up network namespacing");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up network namespacing: %m");
}
}
@@ -2836,25 +2799,21 @@ static int exec_child(
r = apply_mount_namespace(unit, command, context, params, runtime);
if (r < 0) {
*exit_status = EXIT_NAMESPACE;
- *error_message = strdup("Failed to set up mount namespacing");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up mount namespacing: %m");
}
}
/* Apply just after mount namespace setup */
r = apply_working_directory(context, params, home, needs_mount_namespace, exit_status);
- if (r < 0) {
- *error_message = strdup("Changing to the requested working directory failed");
- return r;
- }
+ if (r < 0)
+ return log_unit_error_errno(unit, r, "Changing to the requested working directory failed: %m");
/* Drop groups as early as possbile */
if (needs_setuid) {
r = enforce_groups(context, gid, supplementary_gids, ngids);
if (r < 0) {
- *error_message = strdup("Changing group credentials failed");
*exit_status = EXIT_GROUP;
- return r;
+ return log_unit_error_errno(unit, r, "Changing group credentials failed: %m");
}
}
@@ -2863,9 +2822,8 @@ static int exec_child(
if (use_selinux && params->selinux_context_net && socket_fd >= 0) {
r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
if (r < 0) {
- *error_message = strdup("Failed to determine SELinux context");
*exit_status = EXIT_SELINUX_CONTEXT;
- return r;
+ return log_unit_error_errno(unit, r, "Failed to determine SELinux context: %m");
}
}
#endif
@@ -2873,9 +2831,8 @@ static int exec_child(
if (context->private_users) {
r = setup_private_users(uid, gid);
if (r < 0) {
- *error_message = strdup("Failed to set up user namespacing");
*exit_status = EXIT_USER;
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up user namespacing: %m");
}
}
}
@@ -2889,9 +2846,8 @@ static int exec_child(
if (r >= 0)
r = flags_fds(fds, n_storage_fds, n_socket_fds, context->non_blocking);
if (r < 0) {
- *error_message = strdup("Failed to adjust passed file descriptors");
*exit_status = EXIT_FDS;
- return r;
+ return log_unit_error_errno(unit, r, "Failed to adjust passed file descriptors: %m");
}
secure_bits = context->secure_bits;
@@ -2906,18 +2862,16 @@ static int exec_child(
r = setrlimit_closest(i, context->rlimit[i]);
if (r < 0) {
- *error_message = strdup("Failed to adjust resource limits");
*exit_status = EXIT_LIMITS;
- return r;
+ return log_unit_error_errno(unit, r, "Failed to adjust resource limit %s: %m", rlimit_to_string(i));
}
}
/* Set the RTPRIO resource limit to 0, but only if nothing else was explicitly requested. */
if (context->restrict_realtime && !context->rlimit[RLIMIT_RTPRIO]) {
if (setrlimit(RLIMIT_RTPRIO, &RLIMIT_MAKE_CONST(0)) < 0) {
- *error_message = strdup("Failed to adjust RLIMIT_RTPRIO resource limit");
*exit_status = EXIT_LIMITS;
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to adjust RLIMIT_RTPRIO resource limit: %m");
}
}
@@ -2934,8 +2888,7 @@ static int exec_child(
r = capability_bounding_set_drop(bset, false);
if (r < 0) {
*exit_status = EXIT_CAPABILITIES;
- *error_message = strdup("Failed to drop capabilities");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to drop capabilities: %m");
}
}
@@ -2946,8 +2899,7 @@ static int exec_child(
r = capability_ambient_set_apply(context->capability_ambient_set, true);
if (r < 0) {
*exit_status = EXIT_CAPABILITIES;
- *error_message = strdup("Failed to apply ambient capabilities (before UID change)");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply ambient capabilities (before UID change): %m");
}
}
}
@@ -2957,8 +2909,7 @@ static int exec_child(
r = enforce_user(context, uid);
if (r < 0) {
*exit_status = EXIT_USER;
- (void) asprintf(error_message, "Failed to change UID to "UID_FMT, uid);
- return r;
+ return log_unit_error_errno(unit, r, "Failed to change UID to " UID_FMT ": %m", uid);
}
if (!needs_ambient_hack &&
@@ -2968,8 +2919,7 @@ static int exec_child(
r = capability_ambient_set_apply(context->capability_ambient_set, false);
if (r < 0) {
*exit_status = EXIT_CAPABILITIES;
- *error_message = strdup("Failed to apply ambient capabilities (after UID change)");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply ambient capabilities (after UID change): %m");
}
/* If we were asked to change user and ambient capabilities
@@ -2998,8 +2948,7 @@ static int exec_child(
r = setexeccon(exec_context);
if (r < 0) {
*exit_status = EXIT_SELINUX_CONTEXT;
- (void) asprintf(error_message, "Failed to change SELinux context to %s", exec_context);
- return r;
+ return log_unit_error_errno(unit, r, "Failed to change SELinux context to %s: %m", exec_context);
}
}
}
@@ -3010,8 +2959,7 @@ static int exec_child(
r = setup_smack(context, command);
if (r < 0) {
*exit_status = EXIT_SMACK_PROCESS_LABEL;
- *error_message = strdup("Failed to set SMACK process label");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set SMACK process label: %m");
}
}
#endif
@@ -3021,10 +2969,7 @@ static int exec_child(
r = aa_change_onexec(context->apparmor_profile);
if (r < 0 && !context->apparmor_profile_ignore) {
*exit_status = EXIT_APPARMOR_PROFILE;
- (void) asprintf(error_message,
- "Failed to prepare AppArmor profile change to %s",
- context->apparmor_profile);
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to prepare AppArmor profile change to %s: %m", context->apparmor_profile);
}
}
#endif
@@ -3034,79 +2979,68 @@ static int exec_child(
if (prctl(PR_GET_SECUREBITS) != secure_bits)
if (prctl(PR_SET_SECUREBITS, secure_bits) < 0) {
*exit_status = EXIT_SECUREBITS;
- *error_message = strdup("Failed to set process secure bits");
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to set process secure bits: %m");
}
if (context_has_no_new_privileges(context))
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
*exit_status = EXIT_NO_NEW_PRIVILEGES;
- *error_message = strdup("Failed to disable new privileges");
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to disable new privileges: %m");
}
#ifdef HAVE_SECCOMP
r = apply_address_families(unit, context);
if (r < 0) {
*exit_status = EXIT_ADDRESS_FAMILIES;
- *error_message = strdup("Failed to restrict address families");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to restrict address families: %m");
}
r = apply_memory_deny_write_execute(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to disable writing to executable memory");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to disable writing to executable memory: %m");
}
r = apply_restrict_realtime(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to apply realtime restrictions");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply realtime restrictions: %m");
}
r = apply_restrict_namespaces(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to apply namespace restrictions");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply namespace restrictions: %m");
}
r = apply_protect_sysctl(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to apply sysctl restrictions");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply sysctl restrictions: %m");
}
r = apply_protect_kernel_modules(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to apply module loading restrictions");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply module loading restrictions: %m");
}
r = apply_private_devices(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to set up private devices");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up private devices: %m");
}
r = apply_syscall_archs(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to apply syscall architecture restrictions");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply syscall architecture restrictions: %m");
}
r = apply_lock_personality(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to lock personalities");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to lock personalities: %m");
}
/* This really should remain the last step before the execve(), to make sure our own code is unaffected
@@ -3114,8 +3048,7 @@ static int exec_child(
r = apply_syscall_filter(unit, context, needs_ambient_hack);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to apply system call filters");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply system call filters: %m");
}
#endif
}
@@ -3126,7 +3059,7 @@ static int exec_child(
ee = strv_env_delete(accum_env, 1, context->unset_environment);
if (!ee) {
*exit_status = EXIT_MEMORY;
- return -ENOMEM;
+ return log_oom();
}
strv_free(accum_env);
@@ -3136,8 +3069,7 @@ static int exec_child(
final_argv = replace_env_argv(argv, accum_env);
if (!final_argv) {
*exit_status = EXIT_MEMORY;
- *error_message = strdup("Failed to prepare process arguments");
- return -ENOMEM;
+ return log_oom();
}
if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
@@ -3145,20 +3077,33 @@ static int exec_child(
line = exec_command_line(final_argv);
if (line) {
- log_open();
log_struct(LOG_DEBUG,
"EXECUTABLE=%s", command->path,
LOG_UNIT_MESSAGE(unit, "Executing: %s", line),
LOG_UNIT_ID(unit),
LOG_UNIT_INVOCATION_ID(unit),
NULL);
- log_close();
}
}
execve(command->path, final_argv, accum_env);
+
+ if (errno == ENOENT && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) {
+
+ log_struct_errno(LOG_INFO, errno,
+ "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
+ LOG_UNIT_ID(unit),
+ LOG_UNIT_INVOCATION_ID(unit),
+ LOG_UNIT_MESSAGE(unit, "Executable %s missing, skipping: %m",
+ command->path),
+ "EXECUTABLE=%s", command->path,
+ NULL);
+
+ return 0;
+ }
+
*exit_status = EXIT_EXEC;
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to execute command: %m");
}
int exec_spawn(Unit *unit,
@@ -3226,13 +3171,13 @@ int exec_spawn(Unit *unit,
LOG_UNIT_ID(unit),
LOG_UNIT_INVOCATION_ID(unit),
NULL);
+
pid = fork();
if (pid < 0)
return log_unit_error_errno(unit, errno, "Failed to fork: %m");
if (pid == 0) {
- int exit_status;
- _cleanup_free_ char *error_message = NULL;
+ int exit_status = EXIT_SUCCESS;
r = exec_child(unit,
command,
@@ -3248,38 +3193,18 @@ int exec_spawn(Unit *unit,
n_socket_fds,
files_env,
unit->manager->user_lookup_fds[1],
- &exit_status,
- &error_message);
+ &exit_status);
+
if (r < 0) {
- log_open();
- if (error_message)
- log_struct_errno(LOG_ERR, r,
- "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
- LOG_UNIT_ID(unit),
- LOG_UNIT_INVOCATION_ID(unit),
- LOG_UNIT_MESSAGE(unit, "%s: %m",
- error_message),
- "EXECUTABLE=%s", command->path,
- NULL);
- else if (r == -ENOENT && (command->flags & EXEC_COMMAND_IGNORE_FAILURE))
- log_struct_errno(LOG_INFO, r,
- "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
- LOG_UNIT_ID(unit),
- LOG_UNIT_INVOCATION_ID(unit),
- LOG_UNIT_MESSAGE(unit, "Skipped spawning %s: %m",
- command->path),
- "EXECUTABLE=%s", command->path,
- NULL);
- else
- log_struct_errno(LOG_ERR, r,
- "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
- LOG_UNIT_ID(unit),
- LOG_UNIT_INVOCATION_ID(unit),
- LOG_UNIT_MESSAGE(unit, "Failed at step %s spawning %s: %m",
- exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD),
- command->path),
- "EXECUTABLE=%s", command->path,
- NULL);
+ log_struct_errno(LOG_ERR, r,
+ "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
+ LOG_UNIT_ID(unit),
+ LOG_UNIT_INVOCATION_ID(unit),
+ LOG_UNIT_MESSAGE(unit, "Failed at step %s spawning %s: %m",
+ exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD),
+ command->path),
+ "EXECUTABLE=%s", command->path,
+ NULL);
}
_exit(exit_status);