core: make ExecRuntime be manager managed object
Before this, each ExecRuntime object is owned by a unit. However, it may be shared with other units which enable JoinsNamespaceOf=. Thus, by the serialization/deserialization process, its sharing information, more specifically, reference counter is lost, and causes issue #7790. This makes ExecRuntime objects be managed by manager, and changes the serialization/deserialization process. Fixes #7790.
This commit is contained in:
parent
960c7c2791
commit
e8a565cb66
|
@ -82,6 +82,7 @@
|
||||||
#include "label.h"
|
#include "label.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "manager.h"
|
||||||
#include "missing.h"
|
#include "missing.h"
|
||||||
#include "mkdir.h"
|
#include "mkdir.h"
|
||||||
#include "namespace.h"
|
#include "namespace.h"
|
||||||
|
@ -4523,182 +4524,6 @@ int exec_command_append(ExecCommand *c, const char *path, ...) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int exec_runtime_allocate(ExecRuntime **rt) {
|
|
||||||
|
|
||||||
if (*rt)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
*rt = new0(ExecRuntime, 1);
|
|
||||||
if (!*rt)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
(*rt)->n_ref = 1;
|
|
||||||
(*rt)->netns_storage_socket[0] = (*rt)->netns_storage_socket[1] = -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int exec_runtime_make(ExecRuntime **rt, ExecContext *c, const char *id) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(rt);
|
|
||||||
assert(c);
|
|
||||||
assert(id);
|
|
||||||
|
|
||||||
if (*rt)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (!c->private_network && !c->private_tmp)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
r = exec_runtime_allocate(rt);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (c->private_network && (*rt)->netns_storage_socket[0] < 0) {
|
|
||||||
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, (*rt)->netns_storage_socket) < 0)
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c->private_tmp && !(*rt)->tmp_dir) {
|
|
||||||
r = setup_tmp_dirs(id, &(*rt)->tmp_dir, &(*rt)->var_tmp_dir);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExecRuntime *exec_runtime_ref(ExecRuntime *r) {
|
|
||||||
assert(r);
|
|
||||||
assert(r->n_ref > 0);
|
|
||||||
|
|
||||||
r->n_ref++;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExecRuntime *exec_runtime_unref(ExecRuntime *r) {
|
|
||||||
|
|
||||||
if (!r)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
assert(r->n_ref > 0);
|
|
||||||
|
|
||||||
r->n_ref--;
|
|
||||||
if (r->n_ref > 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
free(r->tmp_dir);
|
|
||||||
free(r->var_tmp_dir);
|
|
||||||
safe_close_pair(r->netns_storage_socket);
|
|
||||||
return mfree(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
int exec_runtime_serialize(Unit *u, ExecRuntime *rt, FILE *f, FDSet *fds) {
|
|
||||||
assert(u);
|
|
||||||
assert(f);
|
|
||||||
assert(fds);
|
|
||||||
|
|
||||||
if (!rt)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (rt->tmp_dir)
|
|
||||||
unit_serialize_item(u, f, "tmp-dir", rt->tmp_dir);
|
|
||||||
|
|
||||||
if (rt->var_tmp_dir)
|
|
||||||
unit_serialize_item(u, f, "var-tmp-dir", rt->var_tmp_dir);
|
|
||||||
|
|
||||||
if (rt->netns_storage_socket[0] >= 0) {
|
|
||||||
int copy;
|
|
||||||
|
|
||||||
copy = fdset_put_dup(fds, rt->netns_storage_socket[0]);
|
|
||||||
if (copy < 0)
|
|
||||||
return copy;
|
|
||||||
|
|
||||||
unit_serialize_item_format(u, f, "netns-socket-0", "%i", copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rt->netns_storage_socket[1] >= 0) {
|
|
||||||
int copy;
|
|
||||||
|
|
||||||
copy = fdset_put_dup(fds, rt->netns_storage_socket[1]);
|
|
||||||
if (copy < 0)
|
|
||||||
return copy;
|
|
||||||
|
|
||||||
unit_serialize_item_format(u, f, "netns-socket-1", "%i", copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int exec_runtime_deserialize_item(Unit *u, ExecRuntime **rt, const char *key, const char *value, FDSet *fds) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(rt);
|
|
||||||
assert(key);
|
|
||||||
assert(value);
|
|
||||||
|
|
||||||
if (streq(key, "tmp-dir")) {
|
|
||||||
char *copy;
|
|
||||||
|
|
||||||
r = exec_runtime_allocate(rt);
|
|
||||||
if (r < 0)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
copy = strdup(value);
|
|
||||||
if (!copy)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
free((*rt)->tmp_dir);
|
|
||||||
(*rt)->tmp_dir = copy;
|
|
||||||
|
|
||||||
} else if (streq(key, "var-tmp-dir")) {
|
|
||||||
char *copy;
|
|
||||||
|
|
||||||
r = exec_runtime_allocate(rt);
|
|
||||||
if (r < 0)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
copy = strdup(value);
|
|
||||||
if (!copy)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
free((*rt)->var_tmp_dir);
|
|
||||||
(*rt)->var_tmp_dir = copy;
|
|
||||||
|
|
||||||
} else if (streq(key, "netns-socket-0")) {
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
r = exec_runtime_allocate(rt);
|
|
||||||
if (r < 0)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd))
|
|
||||||
log_unit_debug(u, "Failed to parse netns socket value: %s", value);
|
|
||||||
else {
|
|
||||||
safe_close((*rt)->netns_storage_socket[0]);
|
|
||||||
(*rt)->netns_storage_socket[0] = fdset_remove(fds, fd);
|
|
||||||
}
|
|
||||||
} else if (streq(key, "netns-socket-1")) {
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
r = exec_runtime_allocate(rt);
|
|
||||||
if (r < 0)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd))
|
|
||||||
log_unit_debug(u, "Failed to parse netns socket value: %s", value);
|
|
||||||
else {
|
|
||||||
safe_close((*rt)->netns_storage_socket[1]);
|
|
||||||
(*rt)->netns_storage_socket[1] = fdset_remove(fds, fd);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *remove_tmpdir_thread(void *p) {
|
static void *remove_tmpdir_thread(void *p) {
|
||||||
_cleanup_free_ char *path = p;
|
_cleanup_free_ char *path = p;
|
||||||
|
|
||||||
|
@ -4706,17 +4531,17 @@ static void *remove_tmpdir_thread(void *p) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void exec_runtime_destroy(ExecRuntime *rt) {
|
static ExecRuntime* exec_runtime_free(ExecRuntime *rt, bool destroy) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!rt)
|
if (!rt)
|
||||||
return;
|
return NULL;
|
||||||
|
|
||||||
/* If there are multiple users of this, let's leave the stuff around */
|
if (rt->manager)
|
||||||
if (rt->n_ref > 1)
|
(void) hashmap_remove(rt->manager->exec_runtime_by_id, rt->id);
|
||||||
return;
|
|
||||||
|
|
||||||
if (rt->tmp_dir) {
|
/* When destroy is true, then rm_rf tmp_dir and var_tmp_dir. */
|
||||||
|
if (destroy && rt->tmp_dir) {
|
||||||
log_debug("Spawning thread to nuke %s", rt->tmp_dir);
|
log_debug("Spawning thread to nuke %s", rt->tmp_dir);
|
||||||
|
|
||||||
r = asynchronous_job(remove_tmpdir_thread, rt->tmp_dir);
|
r = asynchronous_job(remove_tmpdir_thread, rt->tmp_dir);
|
||||||
|
@ -4728,7 +4553,7 @@ void exec_runtime_destroy(ExecRuntime *rt) {
|
||||||
rt->tmp_dir = NULL;
|
rt->tmp_dir = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rt->var_tmp_dir) {
|
if (destroy && rt->var_tmp_dir) {
|
||||||
log_debug("Spawning thread to nuke %s", rt->var_tmp_dir);
|
log_debug("Spawning thread to nuke %s", rt->var_tmp_dir);
|
||||||
|
|
||||||
r = asynchronous_job(remove_tmpdir_thread, rt->var_tmp_dir);
|
r = asynchronous_job(remove_tmpdir_thread, rt->var_tmp_dir);
|
||||||
|
@ -4740,7 +4565,391 @@ void exec_runtime_destroy(ExecRuntime *rt) {
|
||||||
rt->var_tmp_dir = NULL;
|
rt->var_tmp_dir = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rt->id = mfree(rt->id);
|
||||||
|
rt->tmp_dir = mfree(rt->tmp_dir);
|
||||||
|
rt->var_tmp_dir = mfree(rt->var_tmp_dir);
|
||||||
safe_close_pair(rt->netns_storage_socket);
|
safe_close_pair(rt->netns_storage_socket);
|
||||||
|
return mfree(rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exec_runtime_freep(ExecRuntime **rt) {
|
||||||
|
if (*rt)
|
||||||
|
(void) exec_runtime_free(*rt, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int exec_runtime_allocate(ExecRuntime **rt) {
|
||||||
|
assert(rt);
|
||||||
|
|
||||||
|
*rt = new0(ExecRuntime, 1);
|
||||||
|
if (!*rt)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
(*rt)->netns_storage_socket[0] = (*rt)->netns_storage_socket[1] = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int exec_runtime_add(
|
||||||
|
Manager *m,
|
||||||
|
const char *id,
|
||||||
|
const char *tmp_dir,
|
||||||
|
const char *var_tmp_dir,
|
||||||
|
const int netns_storage_socket[2],
|
||||||
|
ExecRuntime **ret) {
|
||||||
|
|
||||||
|
_cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(m);
|
||||||
|
assert(id);
|
||||||
|
|
||||||
|
r = hashmap_ensure_allocated(&m->exec_runtime_by_id, &string_hash_ops);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = exec_runtime_allocate(&rt);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
rt->id = strdup(id);
|
||||||
|
if (!rt->id)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (tmp_dir) {
|
||||||
|
rt->tmp_dir = strdup(tmp_dir);
|
||||||
|
if (!rt->tmp_dir)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* When tmp_dir is set, then we require var_tmp_dir is also set. */
|
||||||
|
assert(var_tmp_dir);
|
||||||
|
rt->var_tmp_dir = strdup(var_tmp_dir);
|
||||||
|
if (!rt->var_tmp_dir)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (netns_storage_socket) {
|
||||||
|
rt->netns_storage_socket[0] = netns_storage_socket[0];
|
||||||
|
rt->netns_storage_socket[1] = netns_storage_socket[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
r = hashmap_put(m->exec_runtime_by_id, rt->id, rt);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
rt->manager = m;
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
*ret = rt;
|
||||||
|
|
||||||
|
/* do not remove created ExecRuntime object when the operation succeeds. */
|
||||||
|
rt = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int exec_runtime_make(Manager *m, const ExecContext *c, const char *id, ExecRuntime **ret) {
|
||||||
|
_cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
|
||||||
|
_cleanup_close_pair_ int netns_storage_socket[2] = {-1, -1};
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(m);
|
||||||
|
assert(c);
|
||||||
|
assert(id);
|
||||||
|
|
||||||
|
/* It is not necessary to create ExecRuntime object. */
|
||||||
|
if (!c->private_network && !c->private_tmp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (c->private_tmp) {
|
||||||
|
r = setup_tmp_dirs(id, &tmp_dir, &var_tmp_dir);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->private_network) {
|
||||||
|
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, netns_storage_socket) < 0)
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = exec_runtime_add(m, id, tmp_dir, var_tmp_dir, netns_storage_socket, ret);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* Avoid cleanup */
|
||||||
|
netns_storage_socket[0] = -1;
|
||||||
|
netns_storage_socket[1] = -1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int exec_runtime_acquire(Manager *m, const ExecContext *c, const char *id, bool create, ExecRuntime **ret) {
|
||||||
|
ExecRuntime *rt;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(m);
|
||||||
|
assert(id);
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
rt = hashmap_get(m->exec_runtime_by_id, id);
|
||||||
|
if (rt)
|
||||||
|
/* We already have a ExecRuntime object, let's increase the ref count and reuse it */
|
||||||
|
goto ref;
|
||||||
|
|
||||||
|
if (!create)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* If not found, then create a new object. */
|
||||||
|
r = exec_runtime_make(m, c, id, &rt);
|
||||||
|
if (r <= 0)
|
||||||
|
/* When r == 0, it is not necessary to create ExecRuntime object. */
|
||||||
|
return r;
|
||||||
|
|
||||||
|
ref:
|
||||||
|
/* increment reference counter. */
|
||||||
|
rt->n_ref++;
|
||||||
|
*ret = rt;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecRuntime *exec_runtime_unref(ExecRuntime *rt, bool destroy) {
|
||||||
|
if (!rt)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
assert(rt->n_ref > 0);
|
||||||
|
|
||||||
|
rt->n_ref--;
|
||||||
|
if (rt->n_ref > 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return exec_runtime_free(rt, destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
int exec_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
|
||||||
|
ExecRuntime *rt;
|
||||||
|
Iterator i;
|
||||||
|
|
||||||
|
assert(m);
|
||||||
|
assert(f);
|
||||||
|
assert(fds);
|
||||||
|
|
||||||
|
HASHMAP_FOREACH(rt, m->exec_runtime_by_id, i) {
|
||||||
|
fprintf(f, "exec-runtime=%s", rt->id);
|
||||||
|
|
||||||
|
if (rt->tmp_dir)
|
||||||
|
fprintf(f, " tmp-dir=%s", rt->tmp_dir);
|
||||||
|
|
||||||
|
if (rt->var_tmp_dir)
|
||||||
|
fprintf(f, " var-tmp-dir=%s", rt->var_tmp_dir);
|
||||||
|
|
||||||
|
if (rt->netns_storage_socket[0] >= 0) {
|
||||||
|
int copy;
|
||||||
|
|
||||||
|
copy = fdset_put_dup(fds, rt->netns_storage_socket[0]);
|
||||||
|
if (copy < 0)
|
||||||
|
return copy;
|
||||||
|
|
||||||
|
fprintf(f, " netns-socket-0=%i", copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rt->netns_storage_socket[1] >= 0) {
|
||||||
|
int copy;
|
||||||
|
|
||||||
|
copy = fdset_put_dup(fds, rt->netns_storage_socket[1]);
|
||||||
|
if (copy < 0)
|
||||||
|
return copy;
|
||||||
|
|
||||||
|
fprintf(f, " netns-socket-1=%i", copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
fputc('\n', f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds) {
|
||||||
|
_cleanup_(exec_runtime_freep) ExecRuntime *rt_create = NULL;
|
||||||
|
ExecRuntime *rt;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* This is for the migration from old (v237 or earlier) deserialization text.
|
||||||
|
* Due to the bug #7790, this may not work with the units that use JoinsNamespaceOf=.
|
||||||
|
* Even if the ExecRuntime object originally created by the other unit, we cannot judge
|
||||||
|
* so or not from the serialized text, then we always creates a new object owned by this. */
|
||||||
|
|
||||||
|
assert(u);
|
||||||
|
assert(key);
|
||||||
|
assert(value);
|
||||||
|
|
||||||
|
/* Manager manages ExecRuntime objects by the unit id.
|
||||||
|
* So, we omit the serialized text when the unit does not have id (yet?)... */
|
||||||
|
if (isempty(u->id)) {
|
||||||
|
log_unit_debug(u, "Invocation ID not found. Dropping runtime parameter.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = hashmap_ensure_allocated(&u->manager->exec_runtime_by_id, &string_hash_ops);
|
||||||
|
if (r < 0) {
|
||||||
|
log_unit_debug_errno(u, r, "Failed to allocate storage for runtime parameter: %m");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rt = hashmap_get(u->manager->exec_runtime_by_id, u->id);
|
||||||
|
if (!rt) {
|
||||||
|
r = exec_runtime_allocate(&rt_create);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
rt_create->id = strdup(u->id);
|
||||||
|
if (!rt_create->id)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
rt = rt_create;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(key, "tmp-dir")) {
|
||||||
|
char *copy;
|
||||||
|
|
||||||
|
copy = strdup(value);
|
||||||
|
if (!copy)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
free_and_replace(rt->tmp_dir, copy);
|
||||||
|
|
||||||
|
} else if (streq(key, "var-tmp-dir")) {
|
||||||
|
char *copy;
|
||||||
|
|
||||||
|
copy = strdup(value);
|
||||||
|
if (!copy)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
free_and_replace(rt->var_tmp_dir, copy);
|
||||||
|
|
||||||
|
} else if (streq(key, "netns-socket-0")) {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
|
||||||
|
log_unit_debug(u, "Failed to parse netns socket value: %s", value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_close(rt->netns_storage_socket[0]);
|
||||||
|
rt->netns_storage_socket[0] = fdset_remove(fds, fd);
|
||||||
|
|
||||||
|
} else if (streq(key, "netns-socket-1")) {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
|
||||||
|
log_unit_debug(u, "Failed to parse netns socket value: %s", value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_close(rt->netns_storage_socket[1]);
|
||||||
|
rt->netns_storage_socket[1] = fdset_remove(fds, fd);
|
||||||
|
} else
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
|
/* If the object is newly created, then put it to the hashmap which manages ExecRuntime objects. */
|
||||||
|
if (rt_create) {
|
||||||
|
r = hashmap_put(u->manager->exec_runtime_by_id, rt_create->id, rt_create);
|
||||||
|
if (r < 0) {
|
||||||
|
log_unit_debug_errno(u, r, "Failed to put runtime paramter to manager's storage: %m");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_create->manager = u->manager;
|
||||||
|
|
||||||
|
/* Avoid cleanup */
|
||||||
|
rt_create = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
|
||||||
|
char *id = NULL, *tmp_dir = NULL, *var_tmp_dir = NULL;
|
||||||
|
int r, fd0 = -1, fd1 = -1;
|
||||||
|
const char *p, *v = value;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
assert(m);
|
||||||
|
assert(value);
|
||||||
|
assert(fds);
|
||||||
|
|
||||||
|
n = strcspn(v, " ");
|
||||||
|
id = strndupa(v, n);
|
||||||
|
if (v[n] != ' ')
|
||||||
|
goto finalize;
|
||||||
|
p = v + n + 1;
|
||||||
|
|
||||||
|
v = startswith(p, "tmp-dir=");
|
||||||
|
if (v) {
|
||||||
|
n = strcspn(v, " ");
|
||||||
|
tmp_dir = strndupa(v, n);
|
||||||
|
if (v[n] != ' ')
|
||||||
|
goto finalize;
|
||||||
|
p = v + n + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = startswith(p, "var-tmp-dir=");
|
||||||
|
if (v) {
|
||||||
|
n = strcspn(v, " ");
|
||||||
|
var_tmp_dir = strndupa(v, n);
|
||||||
|
if (v[n] != ' ')
|
||||||
|
goto finalize;
|
||||||
|
p = v + n + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = startswith(p, "netns-socket-0=");
|
||||||
|
if (v) {
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
n = strcspn(v, " ");
|
||||||
|
buf = strndupa(v, n);
|
||||||
|
if (safe_atoi(buf, &fd0) < 0 || !fdset_contains(fds, fd0)) {
|
||||||
|
log_debug("Unable to process exec-runtime netns fd specification.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fd0 = fdset_remove(fds, fd0);
|
||||||
|
if (v[n] != ' ')
|
||||||
|
goto finalize;
|
||||||
|
p = v + n + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = startswith(p, "netns-socket-1=");
|
||||||
|
if (v) {
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
n = strcspn(v, " ");
|
||||||
|
buf = strndupa(v, n);
|
||||||
|
if (safe_atoi(buf, &fd1) < 0 || !fdset_contains(fds, fd1)) {
|
||||||
|
log_debug("Unable to process exec-runtime netns fd specification.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fd1 = fdset_remove(fds, fd1);
|
||||||
|
}
|
||||||
|
|
||||||
|
finalize:
|
||||||
|
|
||||||
|
r = exec_runtime_add(m, id, tmp_dir, var_tmp_dir, (int[]) { fd0, fd1 }, NULL);
|
||||||
|
if (r < 0) {
|
||||||
|
log_debug_errno(r, "Failed to add exec-runtime: %m");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void exec_runtime_vacuum(Manager *m) {
|
||||||
|
ExecRuntime *rt;
|
||||||
|
Iterator i;
|
||||||
|
|
||||||
|
assert(m);
|
||||||
|
|
||||||
|
/* Free unreferenced ExecRuntime objects. This is used after manager deserialization process. */
|
||||||
|
|
||||||
|
HASHMAP_FOREACH(rt, m->exec_runtime_by_id, i) {
|
||||||
|
if (rt->n_ref > 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
(void) exec_runtime_free(rt, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
|
static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
|
||||||
|
|
|
@ -25,6 +25,7 @@ typedef struct ExecCommand ExecCommand;
|
||||||
typedef struct ExecContext ExecContext;
|
typedef struct ExecContext ExecContext;
|
||||||
typedef struct ExecRuntime ExecRuntime;
|
typedef struct ExecRuntime ExecRuntime;
|
||||||
typedef struct ExecParameters ExecParameters;
|
typedef struct ExecParameters ExecParameters;
|
||||||
|
typedef struct Manager Manager;
|
||||||
|
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -120,6 +121,11 @@ struct ExecCommand {
|
||||||
struct ExecRuntime {
|
struct ExecRuntime {
|
||||||
int n_ref;
|
int n_ref;
|
||||||
|
|
||||||
|
Manager *manager;
|
||||||
|
|
||||||
|
/* unit id of the owner */
|
||||||
|
char *id;
|
||||||
|
|
||||||
char *tmp_dir;
|
char *tmp_dir;
|
||||||
char *var_tmp_dir;
|
char *var_tmp_dir;
|
||||||
|
|
||||||
|
@ -374,14 +380,13 @@ void exec_status_start(ExecStatus *s, pid_t pid);
|
||||||
void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status);
|
void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status);
|
||||||
void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix);
|
void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix);
|
||||||
|
|
||||||
int exec_runtime_make(ExecRuntime **rt, ExecContext *c, const char *id);
|
int exec_runtime_acquire(Manager *m, const ExecContext *c, const char *name, bool create, ExecRuntime **ret);
|
||||||
ExecRuntime *exec_runtime_ref(ExecRuntime *r);
|
ExecRuntime *exec_runtime_unref(ExecRuntime *r, bool destroy);
|
||||||
ExecRuntime *exec_runtime_unref(ExecRuntime *r);
|
|
||||||
|
|
||||||
int exec_runtime_serialize(Unit *unit, ExecRuntime *rt, FILE *f, FDSet *fds);
|
int exec_runtime_serialize(const Manager *m, FILE *f, FDSet *fds);
|
||||||
int exec_runtime_deserialize_item(Unit *unit, ExecRuntime **rt, const char *key, const char *value, FDSet *fds);
|
int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds);
|
||||||
|
void exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds);
|
||||||
void exec_runtime_destroy(ExecRuntime *rt);
|
void exec_runtime_vacuum(Manager *m);
|
||||||
|
|
||||||
const char* exec_output_to_string(ExecOutput i) _const_;
|
const char* exec_output_to_string(ExecOutput i) _const_;
|
||||||
ExecOutput exec_output_from_string(const char *s) _pure_;
|
ExecOutput exec_output_from_string(const char *s) _pure_;
|
||||||
|
|
|
@ -1200,6 +1200,9 @@ Manager* manager_free(Manager *m) {
|
||||||
|
|
||||||
bus_done(m);
|
bus_done(m);
|
||||||
|
|
||||||
|
exec_runtime_vacuum(m);
|
||||||
|
hashmap_free(m->exec_runtime_by_id);
|
||||||
|
|
||||||
dynamic_user_vacuum(m, false);
|
dynamic_user_vacuum(m, false);
|
||||||
hashmap_free(m->dynamic_users);
|
hashmap_free(m->dynamic_users);
|
||||||
|
|
||||||
|
@ -1463,6 +1466,8 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
|
||||||
/* Release any dynamic users no longer referenced */
|
/* Release any dynamic users no longer referenced */
|
||||||
dynamic_user_vacuum(m, true);
|
dynamic_user_vacuum(m, true);
|
||||||
|
|
||||||
|
exec_runtime_vacuum(m);
|
||||||
|
|
||||||
/* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
|
/* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
|
||||||
manager_vacuum_uid_refs(m);
|
manager_vacuum_uid_refs(m);
|
||||||
manager_vacuum_gid_refs(m);
|
manager_vacuum_gid_refs(m);
|
||||||
|
@ -2800,6 +2805,10 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
|
||||||
manager_serialize_uid_refs(m, f);
|
manager_serialize_uid_refs(m, f);
|
||||||
manager_serialize_gid_refs(m, f);
|
manager_serialize_gid_refs(m, f);
|
||||||
|
|
||||||
|
r = exec_runtime_serialize(m, f, fds);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
(void) fputc('\n', f);
|
(void) fputc('\n', f);
|
||||||
|
|
||||||
HASHMAP_FOREACH_KEY(u, t, m->units, i) {
|
HASHMAP_FOREACH_KEY(u, t, m->units, i) {
|
||||||
|
@ -2978,6 +2987,8 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
|
||||||
manager_deserialize_uid_refs_one(m, val);
|
manager_deserialize_uid_refs_one(m, val);
|
||||||
else if ((val = startswith(l, "destroy-ipc-gid=")))
|
else if ((val = startswith(l, "destroy-ipc-gid=")))
|
||||||
manager_deserialize_gid_refs_one(m, val);
|
manager_deserialize_gid_refs_one(m, val);
|
||||||
|
else if ((val = startswith(l, "exec-runtime=")))
|
||||||
|
exec_runtime_deserialize_one(m, val, fds);
|
||||||
else if ((val = startswith(l, "subscribed="))) {
|
else if ((val = startswith(l, "subscribed="))) {
|
||||||
|
|
||||||
if (strv_extend(&m->deserialized_subscribed, val) < 0)
|
if (strv_extend(&m->deserialized_subscribed, val) < 0)
|
||||||
|
@ -3082,6 +3093,7 @@ int manager_reload(Manager *m) {
|
||||||
manager_clear_jobs_and_units(m);
|
manager_clear_jobs_and_units(m);
|
||||||
lookup_paths_flush_generator(&m->lookup_paths);
|
lookup_paths_flush_generator(&m->lookup_paths);
|
||||||
lookup_paths_free(&m->lookup_paths);
|
lookup_paths_free(&m->lookup_paths);
|
||||||
|
exec_runtime_vacuum(m);
|
||||||
dynamic_user_vacuum(m, false);
|
dynamic_user_vacuum(m, false);
|
||||||
m->uid_refs = hashmap_free(m->uid_refs);
|
m->uid_refs = hashmap_free(m->uid_refs);
|
||||||
m->gid_refs = hashmap_free(m->gid_refs);
|
m->gid_refs = hashmap_free(m->gid_refs);
|
||||||
|
@ -3140,6 +3152,8 @@ int manager_reload(Manager *m) {
|
||||||
manager_vacuum_uid_refs(m);
|
manager_vacuum_uid_refs(m);
|
||||||
manager_vacuum_gid_refs(m);
|
manager_vacuum_gid_refs(m);
|
||||||
|
|
||||||
|
exec_runtime_vacuum(m);
|
||||||
|
|
||||||
/* It might be safe to log to the journal now. */
|
/* It might be safe to log to the journal now. */
|
||||||
manager_recheck_journal(m);
|
manager_recheck_journal(m);
|
||||||
|
|
||||||
|
|
|
@ -341,6 +341,9 @@ struct Manager {
|
||||||
Hashmap *uid_refs;
|
Hashmap *uid_refs;
|
||||||
Hashmap *gid_refs;
|
Hashmap *gid_refs;
|
||||||
|
|
||||||
|
/* ExecRuntime, indexed by their owner unit id */
|
||||||
|
Hashmap *exec_runtime_by_id;
|
||||||
|
|
||||||
/* When the user hits C-A-D more than 7 times per 2s, do something immediately... */
|
/* When the user hits C-A-D more than 7 times per 2s, do something immediately... */
|
||||||
RateLimit ctrl_alt_del_ratelimit;
|
RateLimit ctrl_alt_del_ratelimit;
|
||||||
EmergencyAction cad_burst_action;
|
EmergencyAction cad_burst_action;
|
||||||
|
|
|
@ -241,7 +241,7 @@ static void mount_done(Unit *u) {
|
||||||
mount_parameters_done(&m->parameters_proc_self_mountinfo);
|
mount_parameters_done(&m->parameters_proc_self_mountinfo);
|
||||||
mount_parameters_done(&m->parameters_fragment);
|
mount_parameters_done(&m->parameters_fragment);
|
||||||
|
|
||||||
m->exec_runtime = exec_runtime_unref(m->exec_runtime);
|
m->exec_runtime = exec_runtime_unref(m->exec_runtime, false);
|
||||||
exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
|
exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
|
||||||
m->control_command = NULL;
|
m->control_command = NULL;
|
||||||
|
|
||||||
|
@ -699,8 +699,10 @@ static int mount_coldplug(Unit *u) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IN_SET(new_state, MOUNT_DEAD, MOUNT_FAILED))
|
if (!IN_SET(new_state, MOUNT_DEAD, MOUNT_FAILED)) {
|
||||||
(void) unit_setup_dynamic_creds(u);
|
(void) unit_setup_dynamic_creds(u);
|
||||||
|
(void) unit_setup_exec_runtime(u);
|
||||||
|
}
|
||||||
|
|
||||||
mount_set_state(m, new_state);
|
mount_set_state(m, new_state);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -813,8 +815,7 @@ static void mount_enter_dead(Mount *m, MountResult f) {
|
||||||
|
|
||||||
mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
|
mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
|
||||||
|
|
||||||
exec_runtime_destroy(m->exec_runtime);
|
m->exec_runtime = exec_runtime_unref(m->exec_runtime, true);
|
||||||
m->exec_runtime = exec_runtime_unref(m->exec_runtime);
|
|
||||||
|
|
||||||
exec_context_destroy_runtime_directory(&m->exec_context, UNIT(m)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
|
exec_context_destroy_runtime_directory(&m->exec_context, UNIT(m)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
|
||||||
|
|
||||||
|
|
|
@ -369,7 +369,7 @@ static void service_done(Unit *u) {
|
||||||
s->pid_file = mfree(s->pid_file);
|
s->pid_file = mfree(s->pid_file);
|
||||||
s->status_text = mfree(s->status_text);
|
s->status_text = mfree(s->status_text);
|
||||||
|
|
||||||
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
|
s->exec_runtime = exec_runtime_unref(s->exec_runtime, false);
|
||||||
exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
|
exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
|
||||||
s->control_command = NULL;
|
s->control_command = NULL;
|
||||||
s->main_command = NULL;
|
s->main_command = NULL;
|
||||||
|
@ -1155,8 +1155,10 @@ static int service_coldplug(Unit *u) {
|
||||||
if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
|
if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
|
||||||
service_start_watchdog(s);
|
service_start_watchdog(s);
|
||||||
|
|
||||||
if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART))
|
if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) {
|
||||||
(void) unit_setup_dynamic_creds(u);
|
(void) unit_setup_dynamic_creds(u);
|
||||||
|
(void) unit_setup_exec_runtime(u);
|
||||||
|
}
|
||||||
|
|
||||||
if (UNIT_ISSET(s->accept_socket)) {
|
if (UNIT_ISSET(s->accept_socket)) {
|
||||||
Socket* socket = SOCKET(UNIT_DEREF(s->accept_socket));
|
Socket* socket = SOCKET(UNIT_DEREF(s->accept_socket));
|
||||||
|
@ -1643,8 +1645,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
|
||||||
s->forbid_restart = false;
|
s->forbid_restart = false;
|
||||||
|
|
||||||
/* We want fresh tmpdirs in case service is started again immediately */
|
/* We want fresh tmpdirs in case service is started again immediately */
|
||||||
exec_runtime_destroy(s->exec_runtime);
|
s->exec_runtime = exec_runtime_unref(s->exec_runtime, true);
|
||||||
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
|
|
||||||
|
|
||||||
if (s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_NO ||
|
if (s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_NO ||
|
||||||
(s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_RESTART && !service_will_restart(UNIT(s))))
|
(s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_RESTART && !service_will_restart(UNIT(s))))
|
||||||
|
|
|
@ -164,7 +164,7 @@ static void socket_done(Unit *u) {
|
||||||
|
|
||||||
s->peers_by_address = set_free(s->peers_by_address);
|
s->peers_by_address = set_free(s->peers_by_address);
|
||||||
|
|
||||||
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
|
s->exec_runtime = exec_runtime_unref(s->exec_runtime, false);
|
||||||
exec_command_free_array(s->exec_command, _SOCKET_EXEC_COMMAND_MAX);
|
exec_command_free_array(s->exec_command, _SOCKET_EXEC_COMMAND_MAX);
|
||||||
s->control_command = NULL;
|
s->control_command = NULL;
|
||||||
|
|
||||||
|
@ -1878,8 +1878,10 @@ static int socket_coldplug(Unit *u) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IN_SET(s->deserialized_state, SOCKET_DEAD, SOCKET_FAILED))
|
if (!IN_SET(s->deserialized_state, SOCKET_DEAD, SOCKET_FAILED)) {
|
||||||
(void) unit_setup_dynamic_creds(u);
|
(void) unit_setup_dynamic_creds(u);
|
||||||
|
(void) unit_setup_exec_runtime(u);
|
||||||
|
}
|
||||||
|
|
||||||
socket_set_state(s, s->deserialized_state);
|
socket_set_state(s, s->deserialized_state);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2017,8 +2019,7 @@ static void socket_enter_dead(Socket *s, SocketResult f) {
|
||||||
|
|
||||||
socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
|
socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
|
||||||
|
|
||||||
exec_runtime_destroy(s->exec_runtime);
|
s->exec_runtime = exec_runtime_unref(s->exec_runtime, true);
|
||||||
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
|
|
||||||
|
|
||||||
exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
|
exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,7 @@ static void swap_done(Unit *u) {
|
||||||
s->parameters_fragment.what = mfree(s->parameters_fragment.what);
|
s->parameters_fragment.what = mfree(s->parameters_fragment.what);
|
||||||
s->parameters_fragment.options = mfree(s->parameters_fragment.options);
|
s->parameters_fragment.options = mfree(s->parameters_fragment.options);
|
||||||
|
|
||||||
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
|
s->exec_runtime = exec_runtime_unref(s->exec_runtime, false);
|
||||||
exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
|
exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
|
||||||
s->control_command = NULL;
|
s->control_command = NULL;
|
||||||
|
|
||||||
|
@ -549,8 +549,10 @@ static int swap_coldplug(Unit *u) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IN_SET(new_state, SWAP_DEAD, SWAP_FAILED))
|
if (!IN_SET(new_state, SWAP_DEAD, SWAP_FAILED)) {
|
||||||
(void) unit_setup_dynamic_creds(u);
|
(void) unit_setup_dynamic_creds(u);
|
||||||
|
(void) unit_setup_exec_runtime(u);
|
||||||
|
}
|
||||||
|
|
||||||
swap_set_state(s, new_state);
|
swap_set_state(s, new_state);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -669,8 +671,7 @@ static void swap_enter_dead(Swap *s, SwapResult f) {
|
||||||
|
|
||||||
swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
|
swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
|
||||||
|
|
||||||
exec_runtime_destroy(s->exec_runtime);
|
s->exec_runtime = exec_runtime_unref(s->exec_runtime, true);
|
||||||
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
|
|
||||||
|
|
||||||
exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
|
exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
|
||||||
|
|
||||||
|
|
|
@ -3176,18 +3176,9 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
|
||||||
assert(fds);
|
assert(fds);
|
||||||
|
|
||||||
if (unit_can_serialize(u)) {
|
if (unit_can_serialize(u)) {
|
||||||
ExecRuntime *rt;
|
|
||||||
|
|
||||||
r = UNIT_VTABLE(u)->serialize(u, f, fds);
|
r = UNIT_VTABLE(u)->serialize(u, f, fds);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
rt = unit_get_exec_runtime(u);
|
|
||||||
if (rt) {
|
|
||||||
r = exec_runtime_serialize(u, rt, f, fds);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dual_timestamp_serialize(f, "state-change-timestamp", &u->state_change_timestamp);
|
dual_timestamp_serialize(f, "state-change-timestamp", &u->state_change_timestamp);
|
||||||
|
@ -3333,18 +3324,12 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *f
|
||||||
}
|
}
|
||||||
|
|
||||||
int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
||||||
ExecRuntime **rt = NULL;
|
|
||||||
size_t offset;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(u);
|
assert(u);
|
||||||
assert(f);
|
assert(f);
|
||||||
assert(fds);
|
assert(fds);
|
||||||
|
|
||||||
offset = UNIT_VTABLE(u)->exec_runtime_offset;
|
|
||||||
if (offset > 0)
|
|
||||||
rt = (ExecRuntime**) ((uint8_t*) u + offset);
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char line[LINE_MAX], *l, *v;
|
char line[LINE_MAX], *l, *v;
|
||||||
CGroupIPAccountingMetric m;
|
CGroupIPAccountingMetric m;
|
||||||
|
@ -3604,18 +3589,16 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unit_can_serialize(u)) {
|
if (unit_can_serialize(u)) {
|
||||||
if (rt) {
|
r = exec_runtime_deserialize_compat(u, l, v, fds);
|
||||||
r = exec_runtime_deserialize_item(u, rt, l, v, fds);
|
if (r < 0) {
|
||||||
if (r < 0) {
|
log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
|
||||||
log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns positive if key was handled by the call */
|
|
||||||
if (r > 0)
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns positive if key was handled by the call */
|
||||||
|
if (r > 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
|
r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);
|
log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);
|
||||||
|
@ -4684,6 +4667,7 @@ int unit_setup_exec_runtime(Unit *u) {
|
||||||
Unit *other;
|
Unit *other;
|
||||||
Iterator i;
|
Iterator i;
|
||||||
void *v;
|
void *v;
|
||||||
|
int r;
|
||||||
|
|
||||||
offset = UNIT_VTABLE(u)->exec_runtime_offset;
|
offset = UNIT_VTABLE(u)->exec_runtime_offset;
|
||||||
assert(offset > 0);
|
assert(offset > 0);
|
||||||
|
@ -4695,15 +4679,12 @@ int unit_setup_exec_runtime(Unit *u) {
|
||||||
|
|
||||||
/* Try to get it from somebody else */
|
/* Try to get it from somebody else */
|
||||||
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_JOINS_NAMESPACE_OF], i) {
|
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_JOINS_NAMESPACE_OF], i) {
|
||||||
|
r = exec_runtime_acquire(u->manager, NULL, other->id, false, rt);
|
||||||
*rt = unit_get_exec_runtime(other);
|
if (r == 1)
|
||||||
if (*rt) {
|
return 1;
|
||||||
exec_runtime_ref(*rt);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return exec_runtime_make(rt, unit_get_exec_context(u), u->id);
|
return exec_runtime_acquire(u->manager, unit_get_exec_context(u), u->id, true, rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
int unit_setup_dynamic_creds(Unit *u) {
|
int unit_setup_dynamic_creds(Unit *u) {
|
||||||
|
|
Loading…
Reference in a new issue