mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
execute: log errors from "sd(EXEC)"
To give the administrator more hints about failures occuring in spawning of commands than just the exit code, log the strerror. All fds are closed, so reopen the log. Related-to: https://bugzilla.redhat.com/show_bug.cgi?id=752901
This commit is contained in:
138
src/execute.c
138
src/execute.c
@@ -989,7 +989,7 @@ int exec_spawn(ExecCommand *command,
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
int i;
|
||||
int i, err;
|
||||
sigset_t ss;
|
||||
const char *username = NULL, *home = NULL;
|
||||
uid_t uid = (uid_t) -1;
|
||||
@@ -1015,6 +1015,7 @@ int exec_spawn(ExecCommand *command,
|
||||
|
||||
if (sigemptyset(&ss) < 0 ||
|
||||
sigprocmask(SIG_SETMASK, &ss, NULL) < 0) {
|
||||
err = -errno;
|
||||
r = EXIT_SIGNAL_MASK;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1023,14 +1024,16 @@ int exec_spawn(ExecCommand *command,
|
||||
* block init reexecution because it cannot bind its
|
||||
* sockets */
|
||||
log_forget_fds();
|
||||
if (close_all_fds(socket_fd >= 0 ? &socket_fd : fds,
|
||||
socket_fd >= 0 ? 1 : n_fds) < 0) {
|
||||
err = close_all_fds(socket_fd >= 0 ? &socket_fd : fds,
|
||||
socket_fd >= 0 ? 1 : n_fds);
|
||||
if (err < 0) {
|
||||
r = EXIT_FDS;
|
||||
goto fail_child;
|
||||
}
|
||||
|
||||
if (!context->same_pgrp)
|
||||
if (setsid() < 0) {
|
||||
err = -errno;
|
||||
r = EXIT_SETSID;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1038,12 +1041,14 @@ int exec_spawn(ExecCommand *command,
|
||||
if (context->tcpwrap_name) {
|
||||
if (socket_fd >= 0)
|
||||
if (!socket_tcpwrap(socket_fd, context->tcpwrap_name)) {
|
||||
err = -EACCES;
|
||||
r = EXIT_TCPWRAP;
|
||||
goto fail_child;
|
||||
}
|
||||
|
||||
for (i = 0; i < (int) n_fds; i++) {
|
||||
if (!socket_tcpwrap(fds[i], context->tcpwrap_name)) {
|
||||
err = -EACCES;
|
||||
r = EXIT_TCPWRAP;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1059,11 +1064,14 @@ int exec_spawn(ExecCommand *command,
|
||||
|
||||
/* Set up terminal for the question */
|
||||
if ((r = setup_confirm_stdio(context,
|
||||
&saved_stdin, &saved_stdout)))
|
||||
&saved_stdin, &saved_stdout))) {
|
||||
err = -errno;
|
||||
goto fail_child;
|
||||
}
|
||||
|
||||
/* Now ask the question. */
|
||||
if (!(line = exec_command_line(argv))) {
|
||||
err = -ENOMEM;
|
||||
r = EXIT_MEMORY;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1072,18 +1080,21 @@ int exec_spawn(ExecCommand *command,
|
||||
free(line);
|
||||
|
||||
if (r < 0 || response == 'n') {
|
||||
err = -ECANCELED;
|
||||
r = EXIT_CONFIRM;
|
||||
goto fail_child;
|
||||
} else if (response == 's') {
|
||||
r = 0;
|
||||
err = r = 0;
|
||||
goto fail_child;
|
||||
}
|
||||
|
||||
/* Release terminal for the question */
|
||||
if ((r = restore_confirm_stdio(context,
|
||||
&saved_stdin, &saved_stdout,
|
||||
&keep_stdin, &keep_stdout)))
|
||||
&keep_stdin, &keep_stdout))) {
|
||||
err = -errno;
|
||||
goto fail_child;
|
||||
}
|
||||
}
|
||||
|
||||
/* If a socket is connected to STDIN/STDOUT/STDERR, we
|
||||
@@ -1091,28 +1102,35 @@ int exec_spawn(ExecCommand *command,
|
||||
if (socket_fd >= 0)
|
||||
fd_nonblock(socket_fd, false);
|
||||
|
||||
if (!keep_stdin)
|
||||
if (setup_input(context, socket_fd, apply_tty_stdin) < 0) {
|
||||
if (!keep_stdin) {
|
||||
err = setup_input(context, socket_fd, apply_tty_stdin);
|
||||
if (err < 0) {
|
||||
r = EXIT_STDIN;
|
||||
goto fail_child;
|
||||
}
|
||||
}
|
||||
|
||||
if (!keep_stdout)
|
||||
if (setup_output(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin) < 0) {
|
||||
if (!keep_stdout) {
|
||||
err = setup_output(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin);
|
||||
if (err < 0) {
|
||||
r = EXIT_STDOUT;
|
||||
goto fail_child;
|
||||
}
|
||||
}
|
||||
|
||||
if (setup_error(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin) < 0) {
|
||||
err = setup_error(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin);
|
||||
if (err < 0) {
|
||||
r = EXIT_STDERR;
|
||||
goto fail_child;
|
||||
}
|
||||
|
||||
if (cgroup_bondings)
|
||||
if (cgroup_bonding_install_list(cgroup_bondings, 0) < 0) {
|
||||
if (cgroup_bondings) {
|
||||
err = cgroup_bonding_install_list(cgroup_bondings, 0);
|
||||
if (err < 0) {
|
||||
r = EXIT_CGROUP;
|
||||
goto fail_child;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->oom_score_adjust_set) {
|
||||
char t[16];
|
||||
@@ -1133,6 +1151,7 @@ int exec_spawn(ExecCommand *command,
|
||||
|
||||
if (write_one_line_file("/proc/self/oom_adj", t) < 0
|
||||
&& errno != EACCES) {
|
||||
err = -errno;
|
||||
r = EXIT_OOM_ADJUST;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1141,6 +1160,7 @@ int exec_spawn(ExecCommand *command,
|
||||
|
||||
if (context->nice_set)
|
||||
if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
|
||||
err = -errno;
|
||||
r = EXIT_NICE;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1153,6 +1173,7 @@ int exec_spawn(ExecCommand *command,
|
||||
|
||||
if (sched_setscheduler(0, context->cpu_sched_policy |
|
||||
(context->cpu_sched_reset_on_fork ? SCHED_RESET_ON_FORK : 0), ¶m) < 0) {
|
||||
err = -errno;
|
||||
r = EXIT_SETSCHEDULER;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1160,18 +1181,21 @@ int exec_spawn(ExecCommand *command,
|
||||
|
||||
if (context->cpuset)
|
||||
if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
|
||||
err = -errno;
|
||||
r = EXIT_CPUAFFINITY;
|
||||
goto fail_child;
|
||||
}
|
||||
|
||||
if (context->ioprio_set)
|
||||
if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
|
||||
err = -errno;
|
||||
r = EXIT_IOPRIO;
|
||||
goto fail_child;
|
||||
}
|
||||
|
||||
if (context->timer_slack_nsec_set)
|
||||
if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
|
||||
err = -errno;
|
||||
r = EXIT_TIMERSLACK;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1181,36 +1205,45 @@ int exec_spawn(ExecCommand *command,
|
||||
|
||||
if (context->user) {
|
||||
username = context->user;
|
||||
if (get_user_creds(&username, &uid, &gid, &home) < 0) {
|
||||
err = get_user_creds(&username, &uid, &gid, &home);
|
||||
if (err < 0) {
|
||||
r = EXIT_USER;
|
||||
goto fail_child;
|
||||
}
|
||||
|
||||
if (is_terminal_input(context->std_input))
|
||||
if (chown_terminal(STDIN_FILENO, uid) < 0) {
|
||||
if (is_terminal_input(context->std_input)) {
|
||||
err = chown_terminal(STDIN_FILENO, uid);
|
||||
if (err < 0) {
|
||||
r = EXIT_STDIN;
|
||||
goto fail_child;
|
||||
}
|
||||
}
|
||||
|
||||
if (cgroup_bondings && context->control_group_modify)
|
||||
if (cgroup_bonding_set_group_access_list(cgroup_bondings, 0755, uid, gid) < 0 ||
|
||||
cgroup_bonding_set_task_access_list(cgroup_bondings, 0644, uid, gid) < 0) {
|
||||
if (cgroup_bondings && context->control_group_modify) {
|
||||
err = cgroup_bonding_set_group_access_list(cgroup_bondings, 0755, uid, gid);
|
||||
if (err >= 0)
|
||||
err = cgroup_bonding_set_task_access_list(cgroup_bondings, 0644, uid, gid);
|
||||
if (err < 0) {
|
||||
r = EXIT_CGROUP;
|
||||
goto fail_child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (apply_permissions)
|
||||
if (enforce_groups(context, username, gid) < 0) {
|
||||
if (apply_permissions) {
|
||||
err = enforce_groups(context, username, gid);
|
||||
if (err < 0) {
|
||||
r = EXIT_GROUP;
|
||||
goto fail_child;
|
||||
}
|
||||
}
|
||||
|
||||
umask(context->umask);
|
||||
|
||||
#ifdef HAVE_PAM
|
||||
if (context->pam_name && username) {
|
||||
if (setup_pam(context->pam_name, username, context->tty_path, &pam_env, fds, n_fds) != 0) {
|
||||
err = setup_pam(context->pam_name, username, context->tty_path, &pam_env, fds, n_fds);
|
||||
if (err < 0) {
|
||||
r = EXIT_PAM;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1218,6 +1251,7 @@ int exec_spawn(ExecCommand *command,
|
||||
#endif
|
||||
if (context->private_network) {
|
||||
if (unshare(CLONE_NEWNET) < 0) {
|
||||
err = -errno;
|
||||
r = EXIT_NETWORK;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1229,23 +1263,28 @@ int exec_spawn(ExecCommand *command,
|
||||
strv_length(context->read_only_dirs) > 0 ||
|
||||
strv_length(context->inaccessible_dirs) > 0 ||
|
||||
context->mount_flags != MS_SHARED ||
|
||||
context->private_tmp)
|
||||
if ((r = setup_namespace(
|
||||
context->read_write_dirs,
|
||||
context->read_only_dirs,
|
||||
context->inaccessible_dirs,
|
||||
context->private_tmp,
|
||||
context->mount_flags)) < 0)
|
||||
context->private_tmp) {
|
||||
err = setup_namespace(context->read_write_dirs,
|
||||
context->read_only_dirs,
|
||||
context->inaccessible_dirs,
|
||||
context->private_tmp,
|
||||
context->mount_flags);
|
||||
if (err < 0) {
|
||||
r = EXIT_NAMESPACE;
|
||||
goto fail_child;
|
||||
}
|
||||
}
|
||||
|
||||
if (apply_chroot) {
|
||||
if (context->root_directory)
|
||||
if (chroot(context->root_directory) < 0) {
|
||||
err = -errno;
|
||||
r = EXIT_CHROOT;
|
||||
goto fail_child;
|
||||
}
|
||||
|
||||
if (chdir(context->working_directory ? context->working_directory : "/") < 0) {
|
||||
err = -errno;
|
||||
r = EXIT_CHDIR;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1256,11 +1295,13 @@ int exec_spawn(ExecCommand *command,
|
||||
if (asprintf(&d, "%s/%s",
|
||||
context->root_directory ? context->root_directory : "",
|
||||
context->working_directory ? context->working_directory : "") < 0) {
|
||||
err = -ENOMEM;
|
||||
r = EXIT_MEMORY;
|
||||
goto fail_child;
|
||||
}
|
||||
|
||||
if (chdir(d) < 0) {
|
||||
err = -errno;
|
||||
free(d);
|
||||
r = EXIT_CHDIR;
|
||||
goto fail_child;
|
||||
@@ -1271,9 +1312,12 @@ int exec_spawn(ExecCommand *command,
|
||||
|
||||
/* We repeat the fd closing here, to make sure that
|
||||
* nothing is leaked from the PAM modules */
|
||||
if (close_all_fds(fds, n_fds) < 0 ||
|
||||
shift_fds(fds, n_fds) < 0 ||
|
||||
flags_fds(fds, n_fds, context->non_blocking) < 0) {
|
||||
err = close_all_fds(fds, n_fds);
|
||||
if (err >= 0)
|
||||
err = shift_fds(fds, n_fds);
|
||||
if (err >= 0)
|
||||
err = flags_fds(fds, n_fds, context->non_blocking);
|
||||
if (err < 0) {
|
||||
r = EXIT_FDS;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1285,22 +1329,27 @@ int exec_spawn(ExecCommand *command,
|
||||
continue;
|
||||
|
||||
if (setrlimit(i, context->rlimit[i]) < 0) {
|
||||
err = -errno;
|
||||
r = EXIT_LIMITS;
|
||||
goto fail_child;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->capability_bounding_set_drop)
|
||||
if (do_capability_bounding_set_drop(context->capability_bounding_set_drop) < 0) {
|
||||
if (context->capability_bounding_set_drop) {
|
||||
err = do_capability_bounding_set_drop(context->capability_bounding_set_drop);
|
||||
if (err < 0) {
|
||||
r = EXIT_CAPABILITIES;
|
||||
goto fail_child;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->user)
|
||||
if (enforce_user(context, uid) < 0) {
|
||||
if (context->user) {
|
||||
err = enforce_user(context, uid);
|
||||
if (err < 0) {
|
||||
r = EXIT_USER;
|
||||
goto fail_child;
|
||||
}
|
||||
}
|
||||
|
||||
/* PR_GET_SECUREBITS is not privileged, while
|
||||
* PR_SET_SECUREBITS is. So to suppress
|
||||
@@ -1308,18 +1357,21 @@ int exec_spawn(ExecCommand *command,
|
||||
* PR_SET_SECUREBITS unless necessary. */
|
||||
if (prctl(PR_GET_SECUREBITS) != context->secure_bits)
|
||||
if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) {
|
||||
err = -errno;
|
||||
r = EXIT_SECUREBITS;
|
||||
goto fail_child;
|
||||
}
|
||||
|
||||
if (context->capabilities)
|
||||
if (cap_set_proc(context->capabilities) < 0) {
|
||||
err = -errno;
|
||||
r = EXIT_CAPABILITIES;
|
||||
goto fail_child;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(our_env = new0(char*, 7))) {
|
||||
err = -ENOMEM;
|
||||
r = EXIT_MEMORY;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1327,12 +1379,14 @@ int exec_spawn(ExecCommand *command,
|
||||
if (n_fds > 0)
|
||||
if (asprintf(our_env + n_env++, "LISTEN_PID=%lu", (unsigned long) getpid()) < 0 ||
|
||||
asprintf(our_env + n_env++, "LISTEN_FDS=%u", n_fds) < 0) {
|
||||
err = -ENOMEM;
|
||||
r = EXIT_MEMORY;
|
||||
goto fail_child;
|
||||
}
|
||||
|
||||
if (home)
|
||||
if (asprintf(our_env + n_env++, "HOME=%s", home) < 0) {
|
||||
err = -ENOMEM;
|
||||
r = EXIT_MEMORY;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1340,6 +1394,7 @@ int exec_spawn(ExecCommand *command,
|
||||
if (username)
|
||||
if (asprintf(our_env + n_env++, "LOGNAME=%s", username) < 0 ||
|
||||
asprintf(our_env + n_env++, "USER=%s", username) < 0) {
|
||||
err = -ENOMEM;
|
||||
r = EXIT_MEMORY;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1348,6 +1403,7 @@ int exec_spawn(ExecCommand *command,
|
||||
context->std_output == EXEC_OUTPUT_TTY ||
|
||||
context->std_error == EXEC_OUTPUT_TTY)
|
||||
if (!(our_env[n_env++] = strdup(default_term_for_tty(tty_path(context))))) {
|
||||
err = -ENOMEM;
|
||||
r = EXIT_MEMORY;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1362,11 +1418,13 @@ int exec_spawn(ExecCommand *command,
|
||||
files_env,
|
||||
pam_env,
|
||||
NULL))) {
|
||||
err = -ENOMEM;
|
||||
r = EXIT_MEMORY;
|
||||
goto fail_child;
|
||||
}
|
||||
|
||||
if (!(final_argv = replace_env_argv(argv, final_env))) {
|
||||
err = -ENOMEM;
|
||||
r = EXIT_MEMORY;
|
||||
goto fail_child;
|
||||
}
|
||||
@@ -1374,9 +1432,17 @@ int exec_spawn(ExecCommand *command,
|
||||
final_env = strv_env_clean(final_env);
|
||||
|
||||
execve(command->path, final_argv, final_env);
|
||||
err = -errno;
|
||||
r = EXIT_EXEC;
|
||||
|
||||
fail_child:
|
||||
if (r != 0) {
|
||||
log_open();
|
||||
log_warning("Failed at step %s spawning %s: %s",
|
||||
exit_status_to_string(r, EXIT_STATUS_SYSTEMD),
|
||||
command->path, strerror(-err));
|
||||
}
|
||||
|
||||
strv_free(our_env);
|
||||
strv_free(final_env);
|
||||
strv_free(pam_env);
|
||||
|
||||
@@ -119,6 +119,9 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
|
||||
|
||||
case EXIT_NETWORK:
|
||||
return "NETWORK";
|
||||
|
||||
case EXIT_NAMESPACE:
|
||||
return "NAMESPACE";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,8 @@ typedef enum ExitStatus {
|
||||
EXIT_STDERR,
|
||||
EXIT_TCPWRAP,
|
||||
EXIT_PAM,
|
||||
EXIT_NETWORK
|
||||
EXIT_NETWORK,
|
||||
EXIT_NAMESPACE
|
||||
|
||||
} ExitStatus;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user