summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMathieu Tortuyaux <mtortuyaux@microsoft.com>2023-04-25 14:06:59 +0200
committerLennart Poettering <lennart@poettering.net>2023-08-21 11:13:54 +0200
commit41712cd1c0d774d5eac592964f25d798df44a190 (patch)
tree92dea9b9316b744beb2da1ebf33571b46431ca2d /src
parentgenerators: use generator_open_unit_file where appropriate (diff)
downloadsystemd-41712cd1c0d774d5eac592964f25d798df44a190.tar.xz
systemd-41712cd1c0d774d5eac592964f25d798df44a190.zip
sysext: support EXTENSION_RELOAD_MANAGER metadata
This metadata (EXTENSION_RELOAD_MANAGER) can be set to "1" to reload the manager when merging/refreshing/unmerging a system extension image. This can be useful in case the sysext image provides systemd units that need to be loaded. With `--no-reload`, one can deactivate the EXTENSION_RELOAD_MANAGER metadata interpretation. Signed-off-by: Mathieu Tortuyaux <mtortuyaux@microsoft.com>
Diffstat (limited to 'src')
-rw-r--r--src/sysext/sysext.c122
1 files changed, 121 insertions, 1 deletions
diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c
index b043eac562..98640c026b 100644
--- a/src/sysext/sysext.c
+++ b/src/sysext/sysext.c
@@ -7,9 +7,16 @@
#include <sys/mount.h>
#include <unistd.h>
+#include "sd-bus.h"
+
#include "build.h"
+#include "bus-locator.h"
+#include "bus-error.h"
+#include "bus-unit-util.h"
+#include "bus-util.h"
#include "capability-util.h"
#include "chase.h"
+#include "constants.h"
#include "devnum-util.h"
#include "discover-image.h"
#include "dissect-image.h"
@@ -45,6 +52,7 @@ static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
static PagerFlags arg_pager_flags = 0;
static bool arg_legend = true;
static bool arg_force = false;
+static bool arg_no_reload = false;
static int arg_noexec = -1;
static ImagePolicy *arg_image_policy = NULL;
@@ -144,6 +152,87 @@ static int is_our_mount_point(const char *p) {
return true;
}
+static int need_reload(void) {
+ /* Parse the mounted images to find out if we need
+ to reload the daemon. */
+ int r;
+
+ if (arg_no_reload)
+ return false;
+
+ STRV_FOREACH(p, arg_hierarchies) {
+ _cleanup_free_ char *f = NULL, *buf = NULL, *resolved = NULL;
+ _cleanup_strv_free_ char **mounted_extensions = NULL;
+
+ r = chase(*p, arg_root, CHASE_PREFIX_ROOT, &resolved, NULL);
+ if (r == -ENOENT) {
+ log_debug_errno(r, "Hierarchy '%s%s' does not exist, ignoring.", strempty(arg_root), *p);
+ continue;
+ }
+ if (r < 0) {
+ log_warning_errno(r, "Failed to resolve path to hierarchy '%s%s': %m, ignoring.", strempty(arg_root), *p);
+ continue;
+ }
+
+ r = is_our_mount_point(resolved);
+ if (r < 0)
+ return r;
+ if (!r)
+ continue;
+
+ f = path_join(*p, image_class_info[arg_image_class].dot_directory_name, image_class_info[arg_image_class].short_identifier_plural);
+ if (!f)
+ return log_oom();
+
+ r = read_full_file(f, &buf, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to open '%s': %m", f);
+
+ mounted_extensions = strv_split_newlines(buf);
+ if (!mounted_extensions)
+ return log_oom();
+
+ STRV_FOREACH(extension, mounted_extensions) {
+ _cleanup_strv_free_ char **extension_release = NULL;
+ const char *extension_reload_manager = NULL;
+ int b;
+
+ r = load_extension_release_pairs(arg_root, arg_image_class, *extension, /* relax_extension_release_check */ true, &extension_release);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to parse extension-release metadata of %s, ignoring: %m", *extension);
+ continue;
+ }
+
+ extension_reload_manager = strv_env_pairs_get(extension_release, "EXTENSION_RELOAD_MANAGER");
+ if (isempty(extension_reload_manager))
+ continue;
+
+ b = parse_boolean(extension_reload_manager);
+ if (b < 0) {
+ log_warning_errno(b, "Failed to parse the extension metadata to know if the manager needs to be reloaded, ignoring: %m");
+ continue;
+ }
+
+ if (b)
+ /* If at least one extension wants a reload, we reload. */
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int daemon_reload(void) {
+ sd_bus *bus;
+ int r;
+
+ r = bus_connect_system_systemd(&bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get D-Bus connection: %m");
+
+ return bus_service_manager_reload(bus);
+}
+
static int unmerge_hierarchy(const char *p) {
int r;
@@ -169,6 +258,12 @@ static int unmerge_hierarchy(const char *p) {
static int unmerge(void) {
int r, ret = 0;
+ bool need_to_reload;
+
+ r = need_reload();
+ if (r < 0)
+ return r;
+ need_to_reload = r > 0;
STRV_FOREACH(p, arg_hierarchies) {
_cleanup_free_ char *resolved = NULL;
@@ -191,6 +286,12 @@ static int unmerge(void) {
ret = r;
}
+ if (need_to_reload) {
+ r = daemon_reload();
+ if (r < 0)
+ return r;
+ }
+
return ret;
}
@@ -784,7 +885,19 @@ static int merge(Hashmap *images) {
if (r < 0)
return r;
- return r != 123; /* exit code 123 means: didn't do anything */
+ if (r == 123) /* exit code 123 means: didn't do anything */
+ return 0;
+
+ r = need_reload();
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ r = daemon_reload();
+ if (r < 0)
+ return r;
+ }
+
+ return 1;
}
static int image_discover_and_read_metadata(Hashmap **ret_images) {
@@ -955,6 +1068,7 @@ static int verb_help(int argc, char **argv, void *userdata) {
" --json=pretty|short|off\n"
" Generate JSON output\n"
" --force Ignore version incompatibilities\n"
+ " --no-reload Do not reload the service manager\n"
" --image-policy=POLICY\n"
" Specify disk image dissection policy\n"
" --noexec=BOOL Whether to mount extension overlay with noexec\n"
@@ -980,6 +1094,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_FORCE,
ARG_IMAGE_POLICY,
ARG_NOEXEC,
+ ARG_NO_RELOAD,
};
static const struct option options[] = {
@@ -992,6 +1107,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "force", no_argument, NULL, ARG_FORCE },
{ "image-policy", required_argument, NULL, ARG_IMAGE_POLICY },
{ "noexec", required_argument, NULL, ARG_NOEXEC },
+ { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
{}
};
@@ -1049,6 +1165,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_noexec = r;
break;
+ case ARG_NO_RELOAD:
+ arg_no_reload = true;
+ break;
+
case '?':
return -EINVAL;