Merge pull request #20321 from bluca/state_dir_symlink
core: add [State|Runtime|Cache|Logs]DirectorySymlink
This commit is contained in:
+233
-49
@@ -1943,26 +1943,29 @@ static int build_environment(
|
||||
}
|
||||
|
||||
for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
|
||||
_cleanup_free_ char *pre = NULL, *joined = NULL;
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
const char *n;
|
||||
|
||||
if (!p->prefix[t])
|
||||
continue;
|
||||
|
||||
if (strv_isempty(c->directories[t].paths))
|
||||
if (c->directories[t].n_items == 0)
|
||||
continue;
|
||||
|
||||
n = exec_directory_env_name_to_string(t);
|
||||
if (!n)
|
||||
continue;
|
||||
|
||||
pre = strjoin(p->prefix[t], "/");
|
||||
if (!pre)
|
||||
return -ENOMEM;
|
||||
for (size_t i = 0; i < c->directories[t].n_items; i++) {
|
||||
_cleanup_free_ char *prefixed = NULL;
|
||||
|
||||
joined = strv_join_full(c->directories[t].paths, ":", pre, true);
|
||||
if (!joined)
|
||||
return -ENOMEM;
|
||||
prefixed = path_join(p->prefix[t], c->directories[t].items[i].path);
|
||||
if (!prefixed)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!strextend_with_separator(&joined, ":", prefixed))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
x = strjoin(n, "=", joined);
|
||||
if (!x)
|
||||
@@ -2078,15 +2081,15 @@ bool exec_needs_mount_namespace(
|
||||
if (params && !params->prefix[t])
|
||||
continue;
|
||||
|
||||
if (!strv_isempty(context->directories[t].paths))
|
||||
if (context->directories[t].n_items > 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->dynamic_user &&
|
||||
(!strv_isempty(context->directories[EXEC_DIRECTORY_STATE].paths) ||
|
||||
!strv_isempty(context->directories[EXEC_DIRECTORY_CACHE].paths) ||
|
||||
!strv_isempty(context->directories[EXEC_DIRECTORY_LOGS].paths)))
|
||||
(context->directories[EXEC_DIRECTORY_STATE].n_items > 0 ||
|
||||
context->directories[EXEC_DIRECTORY_CACHE].n_items > 0 ||
|
||||
context->directories[EXEC_DIRECTORY_LOGS].n_items > 0))
|
||||
return true;
|
||||
|
||||
if (context->log_namespace)
|
||||
@@ -2268,12 +2271,43 @@ static bool exec_directory_is_private(const ExecContext *context, ExecDirectoryT
|
||||
return true;
|
||||
}
|
||||
|
||||
static int create_many_symlinks(const char *root, const char *source, char **symlinks) {
|
||||
_cleanup_free_ char *src_abs = NULL;
|
||||
char **dst;
|
||||
int r;
|
||||
|
||||
assert(source);
|
||||
|
||||
src_abs = path_join(root, source);
|
||||
if (!src_abs)
|
||||
return -ENOMEM;
|
||||
|
||||
STRV_FOREACH(dst, symlinks) {
|
||||
_cleanup_free_ char *dst_abs = NULL;
|
||||
|
||||
dst_abs = path_join(root, *dst);
|
||||
if (!dst_abs)
|
||||
return -ENOMEM;
|
||||
|
||||
r = mkdir_parents_label(dst_abs, 0755);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = symlink_idempotent(src_abs, dst_abs, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_exec_directory(
|
||||
const ExecContext *context,
|
||||
const ExecParameters *params,
|
||||
uid_t uid,
|
||||
gid_t gid,
|
||||
ExecDirectoryType type,
|
||||
bool needs_mount_namespace,
|
||||
int *exit_status) {
|
||||
|
||||
static const int exit_status_table[_EXEC_DIRECTORY_TYPE_MAX] = {
|
||||
@@ -2283,7 +2317,6 @@ static int setup_exec_directory(
|
||||
[EXEC_DIRECTORY_LOGS] = EXIT_LOGS_DIRECTORY,
|
||||
[EXEC_DIRECTORY_CONFIGURATION] = EXIT_CONFIGURATION_DIRECTORY,
|
||||
};
|
||||
char **rt;
|
||||
int r;
|
||||
|
||||
assert(context);
|
||||
@@ -2301,10 +2334,10 @@ static int setup_exec_directory(
|
||||
gid = 0;
|
||||
}
|
||||
|
||||
STRV_FOREACH(rt, context->directories[type].paths) {
|
||||
for (size_t i = 0; i < context->directories[type].n_items; i++) {
|
||||
_cleanup_free_ char *p = NULL, *pp = NULL;
|
||||
|
||||
p = path_join(params->prefix[type], *rt);
|
||||
p = path_join(params->prefix[type], context->directories[type].items[i].path);
|
||||
if (!p) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
@@ -2351,7 +2384,7 @@ static int setup_exec_directory(
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (!path_extend(&pp, *rt)) {
|
||||
if (!path_extend(&pp, context->directories[type].items[i].path)) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
@@ -2384,7 +2417,9 @@ static int setup_exec_directory(
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* And link it up from the original place */
|
||||
/* And link it up from the original place. Note that if a mount namespace is going to be
|
||||
* used, then this symlink remains on the host, and a new one for the child namespace will
|
||||
* be created later. */
|
||||
r = symlink_idempotent(pp, p, true);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
@@ -2407,7 +2442,7 @@ static int setup_exec_directory(
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
q = path_join(params->prefix[type], "private", *rt);
|
||||
q = path_join(params->prefix[type], "private", context->directories[type].items[i].path);
|
||||
if (!q) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
@@ -2460,7 +2495,7 @@ static int setup_exec_directory(
|
||||
if (((st.st_mode ^ context->directories[type].mode) & 07777) != 0)
|
||||
log_warning("%s \'%s\' already exists but the mode is different. "
|
||||
"(File system: %o %sMode: %o)",
|
||||
exec_directory_type_to_string(type), *rt,
|
||||
exec_directory_type_to_string(type), context->directories[type].items[i].path,
|
||||
st.st_mode & 07777, exec_directory_type_to_string(type), context->directories[type].mode & 07777);
|
||||
|
||||
continue;
|
||||
@@ -2483,6 +2518,17 @@ static int setup_exec_directory(
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* If we are not going to run in a namespace, set up the symlinks - otherwise
|
||||
* they are set up later, to allow configuring empty var/run/etc. */
|
||||
if (!needs_mount_namespace)
|
||||
for (size_t i = 0; i < context->directories[type].n_items; i++) {
|
||||
r = create_many_symlinks(params->prefix[type],
|
||||
context->directories[type].items[i].path,
|
||||
context->directories[type].items[i].symlinks);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
@@ -3032,7 +3078,7 @@ static int compile_bind_mounts(
|
||||
if (!params->prefix[t])
|
||||
continue;
|
||||
|
||||
n += strv_length(context->directories[t].paths);
|
||||
n += context->directories[t].n_items;
|
||||
}
|
||||
|
||||
if (n <= 0) {
|
||||
@@ -3073,12 +3119,10 @@ static int compile_bind_mounts(
|
||||
}
|
||||
|
||||
for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
|
||||
char **suffix;
|
||||
|
||||
if (!params->prefix[t])
|
||||
continue;
|
||||
|
||||
if (strv_isempty(context->directories[t].paths))
|
||||
if (context->directories[t].n_items == 0)
|
||||
continue;
|
||||
|
||||
if (exec_directory_is_private(context, t) &&
|
||||
@@ -3100,13 +3144,13 @@ static int compile_bind_mounts(
|
||||
goto finish;
|
||||
}
|
||||
|
||||
STRV_FOREACH(suffix, context->directories[t].paths) {
|
||||
for (size_t i = 0; i < context->directories[t].n_items; i++) {
|
||||
char *s, *d;
|
||||
|
||||
if (exec_directory_is_private(context, t))
|
||||
s = path_join(params->prefix[t], "private", *suffix);
|
||||
s = path_join(params->prefix[t], "private", context->directories[t].items[i].path);
|
||||
else
|
||||
s = path_join(params->prefix[t], *suffix);
|
||||
s = path_join(params->prefix[t], context->directories[t].items[i].path);
|
||||
if (!s) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
@@ -3117,7 +3161,7 @@ static int compile_bind_mounts(
|
||||
/* When RootDirectory= or RootImage= are set, then the symbolic link to the private
|
||||
* directory is not created on the root directory. So, let's bind-mount the directory
|
||||
* on the 'non-private' place. */
|
||||
d = path_join(params->prefix[t], *suffix);
|
||||
d = path_join(params->prefix[t], context->directories[t].items[i].path);
|
||||
else
|
||||
d = strdup(s);
|
||||
if (!d) {
|
||||
@@ -3150,6 +3194,61 @@ finish:
|
||||
return r;
|
||||
}
|
||||
|
||||
/* ret_symlinks will contain a list of pairs src:dest that describes
|
||||
* the symlinks to create later on. For example, the symlinks needed
|
||||
* to safely give private directories to DynamicUser=1 users. */
|
||||
static int compile_symlinks(
|
||||
const ExecContext *context,
|
||||
const ExecParameters *params,
|
||||
char ***ret_symlinks) {
|
||||
|
||||
_cleanup_strv_free_ char **symlinks = NULL;
|
||||
int r;
|
||||
|
||||
assert(context);
|
||||
assert(params);
|
||||
assert(ret_symlinks);
|
||||
|
||||
for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
|
||||
for (size_t i = 0; i < context->directories[dt].n_items; i++) {
|
||||
_cleanup_free_ char *private_path = NULL, *path = NULL;
|
||||
char **symlink;
|
||||
|
||||
STRV_FOREACH(symlink, context->directories[dt].items[i].symlinks) {
|
||||
_cleanup_free_ char *src_abs = NULL, *dst_abs = NULL;
|
||||
|
||||
src_abs = path_join(params->prefix[dt], context->directories[dt].items[i].path);
|
||||
dst_abs = path_join(params->prefix[dt], *symlink);
|
||||
if (!src_abs || !dst_abs)
|
||||
return -ENOMEM;
|
||||
|
||||
r = strv_consume_pair(&symlinks, TAKE_PTR(src_abs), TAKE_PTR(dst_abs));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!exec_directory_is_private(context, dt))
|
||||
continue;
|
||||
|
||||
private_path = path_join(params->prefix[dt], "private", context->directories[dt].items[i].path);
|
||||
if (!private_path)
|
||||
return -ENOMEM;
|
||||
|
||||
path = path_join(params->prefix[dt], context->directories[dt].items[i].path);
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
r = strv_consume_pair(&symlinks, TAKE_PTR(private_path), TAKE_PTR(path));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
*ret_symlinks = TAKE_PTR(symlinks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool insist_on_sandboxing(
|
||||
const ExecContext *context,
|
||||
const char *root_dir,
|
||||
@@ -3196,7 +3295,7 @@ static int apply_mount_namespace(
|
||||
const ExecRuntime *runtime,
|
||||
char **error_path) {
|
||||
|
||||
_cleanup_strv_free_ char **empty_directories = NULL;
|
||||
_cleanup_strv_free_ char **empty_directories = NULL, **symlinks = NULL;
|
||||
const char *tmp_dir = NULL, *var_tmp_dir = NULL;
|
||||
const char *root_dir = NULL, *root_image = NULL;
|
||||
_cleanup_free_ char *creds_path = NULL, *incoming_dir = NULL, *propagate_dir = NULL;
|
||||
@@ -3219,6 +3318,11 @@ static int apply_mount_namespace(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Symlinks for exec dirs are set up after other mounts, before they are made read-only. */
|
||||
r = compile_symlinks(context, params, &symlinks);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
needs_sandboxing = (params->flags & EXEC_APPLY_SANDBOXING) && !(command_flags & EXEC_COMMAND_FULLY_PRIVILEGED);
|
||||
if (needs_sandboxing) {
|
||||
/* The runtime struct only contains the parent of the private /tmp,
|
||||
@@ -3302,6 +3406,7 @@ static int apply_mount_namespace(
|
||||
needs_sandboxing ? context->exec_paths : NULL,
|
||||
needs_sandboxing ? context->no_exec_paths : NULL,
|
||||
empty_directories,
|
||||
symlinks,
|
||||
bind_mounts,
|
||||
n_bind_mounts,
|
||||
context->temporary_filesystems,
|
||||
@@ -3636,21 +3741,19 @@ static int compile_suggested_paths(const ExecContext *c, const ExecParameters *p
|
||||
* directories. */
|
||||
|
||||
for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
|
||||
char **i;
|
||||
|
||||
if (t == EXEC_DIRECTORY_CONFIGURATION)
|
||||
continue;
|
||||
|
||||
if (!p->prefix[t])
|
||||
continue;
|
||||
|
||||
STRV_FOREACH(i, c->directories[t].paths) {
|
||||
for (size_t i = 0; i < c->directories[t].n_items; i++) {
|
||||
char *e;
|
||||
|
||||
if (exec_directory_is_private(c, t))
|
||||
e = path_join(p->prefix[t], "private", *i);
|
||||
e = path_join(p->prefix[t], "private", c->directories[t].items[i].path);
|
||||
else
|
||||
e = path_join(p->prefix[t], *i);
|
||||
e = path_join(p->prefix[t], c->directories[t].items[i].path);
|
||||
if (!e)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -4170,8 +4273,10 @@ static int exec_child(
|
||||
}
|
||||
}
|
||||
|
||||
needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime);
|
||||
|
||||
for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
|
||||
r = setup_exec_directory(context, params, uid, gid, dt, exit_status);
|
||||
r = setup_exec_directory(context, params, uid, gid, dt, needs_mount_namespace, exit_status);
|
||||
if (r < 0)
|
||||
return log_unit_error_errno(unit, r, "Failed to set up special execution directory in %s: %m", params->prefix[dt]);
|
||||
}
|
||||
@@ -4358,7 +4463,6 @@ static int exec_child(
|
||||
log_unit_warning(unit, "PrivateIPC=yes is configured, but the kernel does not support IPC namespaces, ignoring.");
|
||||
}
|
||||
|
||||
needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime);
|
||||
if (needs_mount_namespace) {
|
||||
_cleanup_free_ char *error_path = NULL;
|
||||
|
||||
@@ -5031,7 +5135,7 @@ void exec_context_done(ExecContext *c) {
|
||||
c->address_families = set_free(c->address_families);
|
||||
|
||||
for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++)
|
||||
c->directories[t].paths = strv_free(c->directories[t].paths);
|
||||
exec_directory_done(&c->directories[t]);
|
||||
|
||||
c->log_level_max = -1;
|
||||
|
||||
@@ -5053,26 +5157,39 @@ void exec_context_done(ExecContext *c) {
|
||||
}
|
||||
|
||||
int exec_context_destroy_runtime_directory(const ExecContext *c, const char *runtime_prefix) {
|
||||
char **i;
|
||||
|
||||
assert(c);
|
||||
|
||||
if (!runtime_prefix)
|
||||
return 0;
|
||||
|
||||
STRV_FOREACH(i, c->directories[EXEC_DIRECTORY_RUNTIME].paths) {
|
||||
for (size_t i = 0; i < c->directories[EXEC_DIRECTORY_RUNTIME].n_items; i++) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
if (exec_directory_is_private(c, EXEC_DIRECTORY_RUNTIME))
|
||||
p = path_join(runtime_prefix, "private", *i);
|
||||
p = path_join(runtime_prefix, "private", c->directories[EXEC_DIRECTORY_RUNTIME].items[i].path);
|
||||
else
|
||||
p = path_join(runtime_prefix, *i);
|
||||
p = path_join(runtime_prefix, c->directories[EXEC_DIRECTORY_RUNTIME].items[i].path);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
/* We execute this synchronously, since we need to be sure this is gone when we start the
|
||||
* service next. */
|
||||
(void) rm_rf(p, REMOVE_ROOT);
|
||||
|
||||
char **symlink;
|
||||
STRV_FOREACH(symlink, c->directories[EXEC_DIRECTORY_RUNTIME].items[i].symlinks) {
|
||||
_cleanup_free_ char *symlink_abs = NULL;
|
||||
|
||||
if (exec_directory_is_private(c, EXEC_DIRECTORY_RUNTIME))
|
||||
symlink_abs = path_join(runtime_prefix, "private", *symlink);
|
||||
else
|
||||
symlink_abs = path_join(runtime_prefix, *symlink);
|
||||
if (!symlink_abs)
|
||||
return -ENOMEM;
|
||||
|
||||
(void) unlink(symlink_abs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -5484,8 +5601,12 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
||||
for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
|
||||
fprintf(f, "%s%sMode: %04o\n", prefix, exec_directory_type_to_string(dt), c->directories[dt].mode);
|
||||
|
||||
STRV_FOREACH(d, c->directories[dt].paths)
|
||||
fprintf(f, "%s%s: %s\n", prefix, exec_directory_type_to_string(dt), *d);
|
||||
for (size_t i = 0; i < c->directories[dt].n_items; i++) {
|
||||
fprintf(f, "%s%s: %s\n", prefix, exec_directory_type_to_string(dt), c->directories[dt].items[i].path);
|
||||
|
||||
STRV_FOREACH(d, c->directories[dt].items[i].symlinks)
|
||||
fprintf(f, "%s%s: %s:%s\n", prefix, exec_directory_type_symlink_to_string(dt), c->directories[dt].items[i].path, *d);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(f, "%sTimeoutCleanSec: %s\n", prefix, FORMAT_TIMESPAN(c->timeout_clean_usec, USEC_PER_SEC));
|
||||
@@ -5959,18 +6080,16 @@ int exec_context_get_clean_directories(
|
||||
assert(ret);
|
||||
|
||||
for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
|
||||
char **i;
|
||||
|
||||
if (!FLAGS_SET(mask, 1U << t))
|
||||
continue;
|
||||
|
||||
if (!prefix[t])
|
||||
continue;
|
||||
|
||||
STRV_FOREACH(i, c->directories[t].paths) {
|
||||
for (size_t i = 0; i < c->directories[t].n_items; i++) {
|
||||
char *j;
|
||||
|
||||
j = path_join(prefix[t], *i);
|
||||
j = path_join(prefix[t], c->directories[t].items[i].path);
|
||||
if (!j)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -5980,7 +6099,18 @@ int exec_context_get_clean_directories(
|
||||
|
||||
/* Also remove private directories unconditionally. */
|
||||
if (t != EXEC_DIRECTORY_CONFIGURATION) {
|
||||
j = path_join(prefix[t], "private", *i);
|
||||
j = path_join(prefix[t], "private", c->directories[t].items[i].path);
|
||||
if (!j)
|
||||
return -ENOMEM;
|
||||
|
||||
r = strv_consume(&l, j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
char **symlink;
|
||||
STRV_FOREACH(symlink, c->directories[t].items[i].symlinks) {
|
||||
j = path_join(prefix[t], *symlink);
|
||||
if (!j)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -6002,7 +6132,7 @@ int exec_context_get_clean_mask(ExecContext *c, ExecCleanMask *ret) {
|
||||
assert(ret);
|
||||
|
||||
for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++)
|
||||
if (!strv_isempty(c->directories[t].paths))
|
||||
if (c->directories[t].n_items > 0)
|
||||
mask |= 1U << t;
|
||||
|
||||
*ret = mask;
|
||||
@@ -6680,6 +6810,49 @@ ExecLoadCredential *exec_load_credential_free(ExecLoadCredential *lc) {
|
||||
return mfree(lc);
|
||||
}
|
||||
|
||||
void exec_directory_done(ExecDirectory *d) {
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < d->n_items; i++) {
|
||||
free(d->items[i].path);
|
||||
strv_free(d->items[i].symlinks);
|
||||
}
|
||||
|
||||
d->items = mfree(d->items);
|
||||
d->n_items = 0;
|
||||
d->mode = 0755;
|
||||
}
|
||||
|
||||
int exec_directory_add(ExecDirectoryItem **d, size_t *n, const char *path, char **symlinks) {
|
||||
_cleanup_strv_free_ char **s = NULL;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
assert(d);
|
||||
assert(n);
|
||||
assert(path);
|
||||
|
||||
p = strdup(path);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
if (symlinks) {
|
||||
s = strv_copy(symlinks);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!GREEDY_REALLOC(*d, *n + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
(*d)[(*n) ++] = (ExecDirectoryItem) {
|
||||
.path = TAKE_PTR(p),
|
||||
.symlinks = TAKE_PTR(s),
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(exec_set_credential_hash_ops, char, string_hash_func, string_compare_func, ExecSetCredential, exec_set_credential_free);
|
||||
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(exec_load_credential_hash_ops, char, string_hash_func, string_compare_func, ExecLoadCredential, exec_load_credential_free);
|
||||
|
||||
@@ -6740,6 +6913,17 @@ static const char* const exec_directory_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType);
|
||||
|
||||
/* This table maps ExecDirectoryType to the symlink setting it is configured with in the unit */
|
||||
static const char* const exec_directory_type_symlink_table[_EXEC_DIRECTORY_TYPE_MAX] = {
|
||||
[EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectorySymlink",
|
||||
[EXEC_DIRECTORY_STATE] = "StateDirectorySymlink",
|
||||
[EXEC_DIRECTORY_CACHE] = "CacheDirectorySymlink",
|
||||
[EXEC_DIRECTORY_LOGS] = "LogsDirectorySymlink",
|
||||
[EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectorySymlink",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_symlink, ExecDirectoryType);
|
||||
|
||||
/* And this table maps ExecDirectoryType too, but to a generic term identifying the type of resource. This
|
||||
* one is supposed to be generic enough to be used for unit types that don't use ExecContext and per-unit
|
||||
* directories, specifically .timer units with their timestamp touch file. */
|
||||
|
||||
Reference in New Issue
Block a user