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;
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);
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)
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);
cmdline = exec_command_line(argv);
if (!cmdline) {
*exit_status = EXIT_MEMORY;
- return -ENOMEM;
+ return log_oom();
}
r = ask_for_confirmation(vc, unit, cmdline);
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;
}
}
/* 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;
}
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");
}
}
&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);
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
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);
}
}
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) {
¶m);
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");
}
}
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");
}
}
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(
&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,
NULL);
if (!accum_env) {
*exit_status = EXIT_MEMORY;
- return -ENOMEM;
+ return log_oom();
}
accum_env = strv_env_clean(accum_env);
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 */
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");
}
}
}
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");
}
}
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");
}
}
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
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");
}
}
}
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;
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");
}
}
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");
}
}
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");
}
}
}
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 &&
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
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);
}
}
}
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
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
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
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
}
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);
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)) {
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,
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,
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);