From: Lennart Poettering Date: Mon, 12 Jul 2010 00:25:42 +0000 (+0200) Subject: execute: optionally ignore return status of invoked commands X-Git-Tag: v3~38 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=b708e7cea941538bfd5e20ce0a723c19b7da7d1d;hp=f1dfb62962fd25c1fba9d9479cb5df2d23e6712d execute: optionally ignore return status of invoked commands --- diff --git a/fixme b/fixme index abdbaf62a..7f34510e2 100644 --- a/fixme +++ b/fixme @@ -35,11 +35,11 @@ * selinux -* Show exit status auf auxiliary programs in systemctl status +* systemctl status $PID, systemctl stop $PID! -* rtkit status +* make shutdown go on even if conflicting units fail to shut down. -* systemctl status $PID, systemctl stop $PID! +* sulogin in den single user mode, mit plymouth --hide davor External: diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 709a448f4..962388342 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -256,7 +256,15 @@ token will be passed as argv[0] to the executed process, followed by the - further arguments specified. Unless + further arguments specified. If the + first token is prefixed with + - an error code of + the command normally considered a + failure is ignored and considered + success. If both - + and @ are used for + the same command the latter must + preceed the latter. Unless Type=forking is set, the process started via this command line will be considered the diff --git a/src/dbus-execute.c b/src/dbus-execute.c index 1ef6f25ae..bb660b185 100644 --- a/src/dbus-execute.c +++ b/src/dbus-execute.c @@ -258,7 +258,7 @@ int bus_execute_append_command(Manager *m, DBusMessageIter *i, const char *prope assert(i); assert(property); - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sasttuii)", &sub)) + if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sasbttuii)", &sub)) return -ENOMEM; LIST_FOREACH(command, c, c) { @@ -283,6 +283,7 @@ int bus_execute_append_command(Manager *m, DBusMessageIter *i, const char *prope status = (int32_t) c->exec_status.status; if (!dbus_message_iter_close_container(&sub2, &sub3) || + !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &c->ignore) || !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.realtime) || !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.realtime) || !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &c->exec_status.pid) || diff --git a/src/dbus-execute.h b/src/dbus-execute.h index 85c390b10..6cd88d41a 100644 --- a/src/dbus-execute.h +++ b/src/dbus-execute.h @@ -88,7 +88,7 @@ " \n" #define BUS_EXEC_COMMAND_INTERFACE(name) \ - " \n" + " \n" #define BUS_EXEC_CONTEXT_PROPERTIES(interface, context) \ { interface, "Environment", bus_property_append_strv, "as", (context).environment }, \ @@ -152,7 +152,7 @@ { interface, prefix "Status", bus_property_append_int, "i", &(estatus).status } #define BUS_EXEC_COMMAND_PROPERTY(interface, command, name) \ - { interface, name, bus_execute_append_command, "a(sasttuii)", (command) } + { interface, name, bus_execute_append_command, "a(sasbttuii)", (command) } int bus_execute_append_output(Manager *m, DBusMessageIter *i, const char *property, void *data); int bus_execute_append_input(Manager *m, DBusMessageIter *i, const char *property, void *data); diff --git a/src/execute.h b/src/execute.h index f93ab7a00..4b3449e26 100644 --- a/src/execute.h +++ b/src/execute.h @@ -87,6 +87,7 @@ struct ExecCommand { char *path; char **argv; ExecStatus exec_status; + bool ignore; LIST_FIELDS(ExecCommand, command); /* useful for chaining commands */ }; diff --git a/src/load-fragment.c b/src/load-fragment.c index 394aa023f..1d40b69c9 100644 --- a/src/load-fragment.c +++ b/src/load-fragment.c @@ -382,7 +382,7 @@ static int config_parse_exec( char *w; size_t l; char *state; - bool honour_argv0, write_to_path; + bool honour_argv0 = false, ignore = false; path = NULL; nce = NULL; @@ -393,9 +393,17 @@ static int config_parse_exec( if (rvalue[0] == 0) break; - honour_argv0 = rvalue[0] == '@'; + if (rvalue[0] == '-') { + ignore = true; + rvalue ++; + } + + if (rvalue[0] == '@') { + honour_argv0 = true; + rvalue ++; + } - if (rvalue[honour_argv0 ? 1 : 0] != '/') { + if (*rvalue != '/') { log_error("[%s:%u] Invalid executable path in command line: %s", filename, line, rvalue); return -EINVAL; } @@ -408,19 +416,18 @@ static int config_parse_exec( k++; } - if (!(n = new(char*, k + (honour_argv0 ? 0 : 1)))) + if (!(n = new(char*, k + !honour_argv0))) return -ENOMEM; k = 0; - write_to_path = honour_argv0; FOREACH_WORD_QUOTED(w, l, rvalue, state) { if (strncmp(w, ";", l) == 0) break; - if (write_to_path) { - if (!(path = cunescape_length(w+1, l-1))) + if (honour_argv0 && w == rvalue) { + assert(!path); + if (!(path = cunescape_length(w, l))) goto fail; - write_to_path = false; } else { if (!(n[k++] = cunescape_length(w, l))) goto fail; @@ -446,6 +453,7 @@ static int config_parse_exec( nce->argv = n; nce->path = path; + nce->ignore = ignore; path_kill_slashes(nce->path); diff --git a/src/service.c b/src/service.c index 481c044b6..f8b4ff6a2 100644 --- a/src/service.c +++ b/src/service.c @@ -2171,7 +2171,6 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { assert(pid >= 0); success = is_clean_exit(code, status); - s->failure = s->failure || !success; if (s->main_pid == pid) { @@ -2181,9 +2180,13 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { if (s->type != SERVICE_FORKING) { assert(s->exec_command[SERVICE_EXEC_START]); s->exec_command[SERVICE_EXEC_START]->exec_status = s->main_exec_status; + + if (s->exec_command[SERVICE_EXEC_START]->ignore) + success = true; } log_debug("%s: main process exited, code=%s, status=%i", u->meta.id, sigchld_code_to_string(code), status); + s->failure = s->failure || !success; /* The service exited, so the service is officially * gone. */ @@ -2230,12 +2233,17 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { } else if (s->control_pid == pid) { - if (s->control_command) + if (s->control_command) { exec_status_exit(&s->control_command->exec_status, pid, code, status); + if (s->control_command->ignore) + success = true; + } + s->control_pid = 0; log_debug("%s: control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status); + s->failure = s->failure || !success; /* If we are shutting things down anyway we * don't care about failing commands. */ diff --git a/src/socket.c b/src/socket.c index 7ff2927af..2d113aef3 100644 --- a/src/socket.c +++ b/src/socket.c @@ -1400,12 +1400,16 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) { s->control_pid = 0; success = is_clean_exit(code, status); - s->failure = s->failure || !success; - if (s->control_command) + if (s->control_command) { exec_status_exit(&s->control_command->exec_status, pid, code, status); + if (s->control_command->ignore) + success = true; + } + log_debug("%s control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status); + s->failure = s->failure || !success; if (s->control_command && s->control_command->command_next && success) { log_debug("%s running next command for state %s", u->meta.id, socket_state_to_string(s->state)); diff --git a/src/systemctl.c b/src/systemctl.c index d1892e4ae..45e900c5f 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -933,6 +933,8 @@ typedef struct ExecStatusInfo { char *path; char **argv; + bool ignore; + usec_t start_timestamp; usec_t exit_timestamp; pid_t pid; @@ -957,6 +959,7 @@ static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) unsigned n; uint32_t pid; int32_t code, status; + dbus_bool_t ignore; assert(i); assert(i); @@ -1002,6 +1005,7 @@ static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) } if (!dbus_message_iter_next(&sub2) || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 || @@ -1009,6 +1013,7 @@ static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0) return -EIO; + i->ignore = ignore; i->start_timestamp = (usec_t) start_timestamp; i->exit_timestamp = (usec_t) exit_timestamp; i->pid = (pid_t) pid; @@ -1535,10 +1540,11 @@ static int print_property(const char *name, DBusMessageIter *iter) { t = strv_join(info.argv, " "); - printf("%s={ path=%s ; argv[]=%s; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n", + printf("%s={ path=%s ; argv[]=%s ; ignore=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n", name, strna(info.path), strna(t), + yes_no(info.ignore), strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)), strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)), (unsigned) info. pid,