execute: optionally ignore return status of invoked commands

This commit is contained in:
Lennart Poettering 2010-07-12 02:25:42 +02:00
parent f1dfb62962
commit b708e7cea9
9 changed files with 57 additions and 21 deletions

8
fixme
View file

@ -35,12 +35,12 @@
* selinux * selinux
* Show exit status auf auxiliary programs in systemctl status
* rtkit status
* systemctl status $PID, systemctl stop $PID! * systemctl status $PID, systemctl stop $PID!
* make shutdown go on even if conflicting units fail to shut down.
* sulogin in den single user mode, mit plymouth --hide davor
External: External:
* patch /etc/init.d/functions with: * patch /etc/init.d/functions with:

View file

@ -256,7 +256,15 @@
token will be passed as token will be passed as
<literal>argv[0]</literal> to the <literal>argv[0]</literal> to the
executed process, followed by the executed process, followed by the
further arguments specified. Unless further arguments specified. If the
first token is prefixed with
<literal>-</literal> an error code of
the command normally considered a
failure is ignored and considered
success. If both <literal>-</literal>
and <literal>@</literal> are used for
the same command the latter must
preceed the latter. Unless
<varname>Type=forking</varname> is <varname>Type=forking</varname> is
set, the process started via this set, the process started via this
command line will be considered the command line will be considered the

View file

@ -258,7 +258,7 @@ int bus_execute_append_command(Manager *m, DBusMessageIter *i, const char *prope
assert(i); assert(i);
assert(property); 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; return -ENOMEM;
LIST_FOREACH(command, c, c) { 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; status = (int32_t) c->exec_status.status;
if (!dbus_message_iter_close_container(&sub2, &sub3) || 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.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_UINT64, &c->exec_status.exit_timestamp.realtime) ||
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &c->exec_status.pid) || !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &c->exec_status.pid) ||

View file

@ -88,7 +88,7 @@
" <property name=\"KillSignal\" type=\"i\" access=\"read\"/>\n" " <property name=\"KillSignal\" type=\"i\" access=\"read\"/>\n"
#define BUS_EXEC_COMMAND_INTERFACE(name) \ #define BUS_EXEC_COMMAND_INTERFACE(name) \
" <property name=\"" name "\" type=\"a(sasttuii)\" access=\"read\"/>\n" " <property name=\"" name "\" type=\"a(sasbttuii)\" access=\"read\"/>\n"
#define BUS_EXEC_CONTEXT_PROPERTIES(interface, context) \ #define BUS_EXEC_CONTEXT_PROPERTIES(interface, context) \
{ interface, "Environment", bus_property_append_strv, "as", (context).environment }, \ { interface, "Environment", bus_property_append_strv, "as", (context).environment }, \
@ -152,7 +152,7 @@
{ interface, prefix "Status", bus_property_append_int, "i", &(estatus).status } { interface, prefix "Status", bus_property_append_int, "i", &(estatus).status }
#define BUS_EXEC_COMMAND_PROPERTY(interface, command, name) \ #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_output(Manager *m, DBusMessageIter *i, const char *property, void *data);
int bus_execute_append_input(Manager *m, DBusMessageIter *i, const char *property, void *data); int bus_execute_append_input(Manager *m, DBusMessageIter *i, const char *property, void *data);

View file

@ -87,6 +87,7 @@ struct ExecCommand {
char *path; char *path;
char **argv; char **argv;
ExecStatus exec_status; ExecStatus exec_status;
bool ignore;
LIST_FIELDS(ExecCommand, command); /* useful for chaining commands */ LIST_FIELDS(ExecCommand, command); /* useful for chaining commands */
}; };

View file

@ -382,7 +382,7 @@ static int config_parse_exec(
char *w; char *w;
size_t l; size_t l;
char *state; char *state;
bool honour_argv0, write_to_path; bool honour_argv0 = false, ignore = false;
path = NULL; path = NULL;
nce = NULL; nce = NULL;
@ -393,9 +393,17 @@ static int config_parse_exec(
if (rvalue[0] == 0) if (rvalue[0] == 0)
break; break;
honour_argv0 = rvalue[0] == '@'; if (rvalue[0] == '-') {
ignore = true;
rvalue ++;
}
if (rvalue[honour_argv0 ? 1 : 0] != '/') { if (rvalue[0] == '@') {
honour_argv0 = true;
rvalue ++;
}
if (*rvalue != '/') {
log_error("[%s:%u] Invalid executable path in command line: %s", filename, line, rvalue); log_error("[%s:%u] Invalid executable path in command line: %s", filename, line, rvalue);
return -EINVAL; return -EINVAL;
} }
@ -408,19 +416,18 @@ static int config_parse_exec(
k++; k++;
} }
if (!(n = new(char*, k + (honour_argv0 ? 0 : 1)))) if (!(n = new(char*, k + !honour_argv0)))
return -ENOMEM; return -ENOMEM;
k = 0; k = 0;
write_to_path = honour_argv0;
FOREACH_WORD_QUOTED(w, l, rvalue, state) { FOREACH_WORD_QUOTED(w, l, rvalue, state) {
if (strncmp(w, ";", l) == 0) if (strncmp(w, ";", l) == 0)
break; break;
if (write_to_path) { if (honour_argv0 && w == rvalue) {
if (!(path = cunescape_length(w+1, l-1))) assert(!path);
if (!(path = cunescape_length(w, l)))
goto fail; goto fail;
write_to_path = false;
} else { } else {
if (!(n[k++] = cunescape_length(w, l))) if (!(n[k++] = cunescape_length(w, l)))
goto fail; goto fail;
@ -446,6 +453,7 @@ static int config_parse_exec(
nce->argv = n; nce->argv = n;
nce->path = path; nce->path = path;
nce->ignore = ignore;
path_kill_slashes(nce->path); path_kill_slashes(nce->path);

View file

@ -2171,7 +2171,6 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
assert(pid >= 0); assert(pid >= 0);
success = is_clean_exit(code, status); success = is_clean_exit(code, status);
s->failure = s->failure || !success;
if (s->main_pid == pid) { 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) { if (s->type != SERVICE_FORKING) {
assert(s->exec_command[SERVICE_EXEC_START]); assert(s->exec_command[SERVICE_EXEC_START]);
s->exec_command[SERVICE_EXEC_START]->exec_status = s->main_exec_status; 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); 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 /* The service exited, so the service is officially
* gone. */ * 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) { } 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); exec_status_exit(&s->control_command->exec_status, pid, code, status);
if (s->control_command->ignore)
success = true;
}
s->control_pid = 0; s->control_pid = 0;
log_debug("%s: control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status); 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 /* If we are shutting things down anyway we
* don't care about failing commands. */ * don't care about failing commands. */

View file

@ -1400,12 +1400,16 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
s->control_pid = 0; s->control_pid = 0;
success = is_clean_exit(code, status); 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); 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); 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) { 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)); log_debug("%s running next command for state %s", u->meta.id, socket_state_to_string(s->state));

View file

@ -933,6 +933,8 @@ typedef struct ExecStatusInfo {
char *path; char *path;
char **argv; char **argv;
bool ignore;
usec_t start_timestamp; usec_t start_timestamp;
usec_t exit_timestamp; usec_t exit_timestamp;
pid_t pid; pid_t pid;
@ -957,6 +959,7 @@ static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i)
unsigned n; unsigned n;
uint32_t pid; uint32_t pid;
int32_t code, status; int32_t code, status;
dbus_bool_t ignore;
assert(i); assert(i);
assert(i); assert(i);
@ -1002,6 +1005,7 @@ static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i)
} }
if (!dbus_message_iter_next(&sub2) || 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, &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_UINT64, &exit_timestamp, true) < 0 ||
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, 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) bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
return -EIO; return -EIO;
i->ignore = ignore;
i->start_timestamp = (usec_t) start_timestamp; i->start_timestamp = (usec_t) start_timestamp;
i->exit_timestamp = (usec_t) exit_timestamp; i->exit_timestamp = (usec_t) exit_timestamp;
i->pid = (pid_t) pid; i->pid = (pid_t) pid;
@ -1535,10 +1540,11 @@ static int print_property(const char *name, DBusMessageIter *iter) {
t = strv_join(info.argv, " "); 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, name,
strna(info.path), strna(info.path),
strna(t), strna(t),
yes_no(info.ignore),
strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)), strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)), strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
(unsigned) info. pid, (unsigned) info. pid,