core: add ExecStartXYZEx= with dbus support for executable prefixes
Closes #11654
This commit is contained in:
+56
-14
@@ -9,6 +9,7 @@
|
||||
#include "condition.h"
|
||||
#include "cpu-set-util.h"
|
||||
#include "escape.h"
|
||||
#include "exec-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "hostname-util.h"
|
||||
#include "in-addr-util.h"
|
||||
@@ -244,19 +245,21 @@ static int bus_append_parse_size(sd_bus_message *m, const char *field, const cha
|
||||
}
|
||||
|
||||
static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) {
|
||||
bool ignore_failure = false, explicit_path = false, done = false;
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
_cleanup_free_ char *path = NULL;
|
||||
bool explicit_path = false, done = false;
|
||||
_cleanup_strv_free_ char **l = NULL, **ex_opts = NULL;
|
||||
_cleanup_free_ char *path = NULL, *upgraded_name = NULL;
|
||||
ExecCommandFlags flags = 0;
|
||||
bool is_ex_prop = endswith(field, "Ex");
|
||||
int r;
|
||||
|
||||
do {
|
||||
switch (*eq) {
|
||||
|
||||
case '-':
|
||||
if (ignore_failure)
|
||||
if (FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE))
|
||||
done = true;
|
||||
else {
|
||||
ignore_failure = true;
|
||||
flags |= EXEC_COMMAND_IGNORE_FAILURE;
|
||||
eq++;
|
||||
}
|
||||
break;
|
||||
@@ -270,11 +273,36 @@ static int bus_append_exec_command(sd_bus_message *m, const char *field, const c
|
||||
}
|
||||
break;
|
||||
|
||||
case ':':
|
||||
if (FLAGS_SET(flags, EXEC_COMMAND_NO_ENV_EXPAND))
|
||||
done = true;
|
||||
else {
|
||||
flags |= EXEC_COMMAND_NO_ENV_EXPAND;
|
||||
eq++;
|
||||
}
|
||||
break;
|
||||
|
||||
case '+':
|
||||
if (flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC))
|
||||
done = true;
|
||||
else {
|
||||
flags |= EXEC_COMMAND_FULLY_PRIVILEGED;
|
||||
eq++;
|
||||
}
|
||||
break;
|
||||
|
||||
case '!':
|
||||
/* The bus API doesn't support +, ! and !! currently, unfortunately. :-( */
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"Sorry, but +, ! and !! are currently not supported for transient services.");
|
||||
if (flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_AMBIENT_MAGIC))
|
||||
done = true;
|
||||
else if (FLAGS_SET(flags, EXEC_COMMAND_NO_SETUID)) {
|
||||
flags &= ~EXEC_COMMAND_NO_SETUID;
|
||||
flags |= EXEC_COMMAND_AMBIENT_MAGIC;
|
||||
eq++;
|
||||
} else {
|
||||
flags |= EXEC_COMMAND_NO_SETUID;
|
||||
eq++;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
done = true;
|
||||
@@ -282,6 +310,20 @@ static int bus_append_exec_command(sd_bus_message *m, const char *field, const c
|
||||
}
|
||||
} while (!done);
|
||||
|
||||
if (!is_ex_prop && (flags & (EXEC_COMMAND_NO_ENV_EXPAND|EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC))) {
|
||||
/* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
|
||||
is_ex_prop = true;
|
||||
upgraded_name = strappend(field, "Ex");
|
||||
if (!upgraded_name)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
if (is_ex_prop) {
|
||||
r = exec_command_flags_to_strv(flags, &ex_opts);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to convert ExecCommandFlags to strv: %m");
|
||||
}
|
||||
|
||||
if (explicit_path) {
|
||||
r = extract_first_word(&eq, &path, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
|
||||
if (r < 0)
|
||||
@@ -296,21 +338,21 @@ static int bus_append_exec_command(sd_bus_message *m, const char *field, const c
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
|
||||
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, upgraded_name ?: field);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'v', "a(sasb)");
|
||||
r = sd_bus_message_open_container(m, 'v', is_ex_prop ? "a(sasas)" : "a(sasb)");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "(sasb)");
|
||||
r = sd_bus_message_open_container(m, 'a', is_ex_prop ? "(sasas)" : "(sasb)");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
if (!strv_isempty(l)) {
|
||||
|
||||
r = sd_bus_message_open_container(m, 'r', "sasb");
|
||||
r = sd_bus_message_open_container(m, 'r', is_ex_prop ? "sasas" : "sasb");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
@@ -322,7 +364,7 @@ static int bus_append_exec_command(sd_bus_message *m, const char *field, const c
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(m, "b", ignore_failure);
|
||||
r = is_ex_prop ? sd_bus_message_append_strv(m, ex_opts) : sd_bus_message_append(m, "b", FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE));
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
@@ -1351,8 +1393,8 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con
|
||||
|
||||
if (STR_IN_SET(field,
|
||||
"ExecStartPre", "ExecStart", "ExecStartPost",
|
||||
"ExecStartPreEx", "ExecStartEx", "ExecStartPostEx",
|
||||
"ExecReload", "ExecStop", "ExecStopPost"))
|
||||
|
||||
return bus_append_exec_command(m, field, eq);
|
||||
|
||||
if (STR_IN_SET(field, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "set.h"
|
||||
#include "signal-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
@@ -365,8 +366,81 @@ static int gather_environment_consume(int fd, void *arg) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int exec_command_flags_from_strv(char **ex_opts, ExecCommandFlags *flags) {
|
||||
ExecCommandFlags ex_flag, ret_flags = 0;
|
||||
char **opt;
|
||||
|
||||
assert(flags);
|
||||
|
||||
STRV_FOREACH(opt, ex_opts) {
|
||||
ex_flag = exec_command_flags_from_string(*opt);
|
||||
if (ex_flag >= 0)
|
||||
ret_flags |= ex_flag;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*flags = ret_flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exec_command_flags_to_strv(ExecCommandFlags flags, char ***ex_opts) {
|
||||
_cleanup_strv_free_ char **ret_opts = NULL;
|
||||
ExecCommandFlags it = flags;
|
||||
const char *str;
|
||||
int i, r;
|
||||
|
||||
assert(ex_opts);
|
||||
|
||||
for (i = 0; it != 0; it &= ~(1 << i), i++) {
|
||||
if (FLAGS_SET(flags, (1 << i))) {
|
||||
str = exec_command_flags_to_string(1 << i);
|
||||
if (!str)
|
||||
return -EINVAL;
|
||||
|
||||
r = strv_extend(&ret_opts, str);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
*ex_opts = TAKE_PTR(ret_opts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const gather_stdout_callback_t gather_environment[] = {
|
||||
gather_environment_generate,
|
||||
gather_environment_collect,
|
||||
gather_environment_consume,
|
||||
};
|
||||
|
||||
static const char* const exec_command_strings[] = {
|
||||
"ignore-failure", /* EXEC_COMMAND_IGNORE_FAILURE */
|
||||
"privileged", /* EXEC_COMMAND_FULLY_PRIVILEGED */
|
||||
"no-setuid", /* EXEC_COMMAND_NO_SETUID */
|
||||
"ambient", /* EXEC_COMMAND_AMBIENT_MAGIC */
|
||||
"no-env-expand", /* EXEC_COMMAND_NO_ENV_EXPAND */
|
||||
};
|
||||
|
||||
const char* exec_command_flags_to_string(ExecCommandFlags i) {
|
||||
size_t idx;
|
||||
|
||||
for (idx = 0; idx < ELEMENTSOF(exec_command_strings); idx++)
|
||||
if (i == (1 << idx))
|
||||
return exec_command_strings[idx];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ExecCommandFlags exec_command_flags_from_string(const char *s) {
|
||||
ssize_t idx;
|
||||
|
||||
idx = string_table_lookup(exec_command_strings, ELEMENTSOF(exec_command_strings), s);
|
||||
|
||||
if (idx < 0)
|
||||
return _EXEC_COMMAND_FLAGS_INVALID;
|
||||
else
|
||||
return 1 << idx;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,15 @@ typedef enum {
|
||||
EXEC_DIR_IGNORE_ERRORS = 1 << 1, /* Ignore non-zero exit status of scripts */
|
||||
} ExecDirFlags;
|
||||
|
||||
typedef enum ExecCommandFlags {
|
||||
EXEC_COMMAND_IGNORE_FAILURE = 1 << 0,
|
||||
EXEC_COMMAND_FULLY_PRIVILEGED = 1 << 1,
|
||||
EXEC_COMMAND_NO_SETUID = 1 << 2,
|
||||
EXEC_COMMAND_AMBIENT_MAGIC = 1 << 3,
|
||||
EXEC_COMMAND_NO_ENV_EXPAND = 1 << 4,
|
||||
_EXEC_COMMAND_FLAGS_INVALID = -1,
|
||||
} ExecCommandFlags;
|
||||
|
||||
int execute_directories(
|
||||
const char* const* directories,
|
||||
usec_t timeout,
|
||||
@@ -29,4 +38,10 @@ int execute_directories(
|
||||
char *envp[],
|
||||
ExecDirFlags flags);
|
||||
|
||||
int exec_command_flags_from_strv(char **ex_opts, ExecCommandFlags *flags);
|
||||
int exec_command_flags_to_strv(ExecCommandFlags flags, char ***ex_opts);
|
||||
|
||||
extern const gather_stdout_callback_t gather_environment[_STDOUT_CONSUME_MAX];
|
||||
|
||||
const char* exec_command_flags_to_string(ExecCommandFlags i);
|
||||
ExecCommandFlags exec_command_flags_from_string(const char *s);
|
||||
|
||||
Reference in New Issue
Block a user