mirror of
https://github.com/systemd/systemd.git
synced 2024-12-21 13:34:21 +03:00
discover-image: introduce per-user image directories
We nowadays support unprivileged invocation of systemd-nspawn + systemd-vmspawn, but there was no support for discovering suitable disk images (i.e. no per-user counterpart of /var/lib/machines). Add this now, and hook it up everywhere. Instead of hardcoding machined's, importd's, portabled's, sysupdated's image discovery to RUNTIME_SCOPE_SYSTEM I introduced a field that make the scope variable, even if this field is always initialized to RUNTIME_SCOPE_SYSTEM for now. I think these four services should eventually be updated to support a per-user concept too, this is preparation for that, even though it doesn't outright add support for this. This is for the largest part not user visible, except for in nspawn, vmspawn and the dissect tool. For the latter I added a pair of --user/--system switches to select the discovery scope.
This commit is contained in:
parent
06ffa66a5b
commit
1c0ade2e1f
@ -503,6 +503,17 @@
|
|||||||
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--system</option></term>
|
||||||
|
<term><option>--user</option></term>
|
||||||
|
|
||||||
|
<listitem><para>When used together with <option>--discover</option> controls whether to search for
|
||||||
|
images installed system-wide or in the user's directories in <varname>$HOME</varname>. If neither
|
||||||
|
switch is specified, will search within both scopes.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<xi:include href="standard-options.xml" xpointer="image-policy-open" />
|
<xi:include href="standard-options.xml" xpointer="image-policy-open" />
|
||||||
<xi:include href="standard-options.xml" xpointer="no-pager" />
|
<xi:include href="standard-options.xml" xpointer="no-pager" />
|
||||||
<xi:include href="standard-options.xml" xpointer="no-legend" />
|
<xi:include href="standard-options.xml" xpointer="no-legend" />
|
||||||
|
@ -29,6 +29,8 @@ _systemd_dissect() {
|
|||||||
local cur=${COMP_WORDS[COMP_CWORD]} prev_1=${COMP_WORDS[COMP_CWORD-1]} prev_2=${COMP_WORDS[COMP_CWORD-2]} words cword
|
local cur=${COMP_WORDS[COMP_CWORD]} prev_1=${COMP_WORDS[COMP_CWORD-1]} prev_2=${COMP_WORDS[COMP_CWORD-2]} words cword
|
||||||
local -A OPTS=(
|
local -A OPTS=(
|
||||||
[STANDALONE]='-h --help --version
|
[STANDALONE]='-h --help --version
|
||||||
|
--user
|
||||||
|
--system
|
||||||
--discover
|
--discover
|
||||||
--no-pager
|
--no-pager
|
||||||
--no-legend
|
--no-legend
|
||||||
|
@ -95,6 +95,7 @@ static char *arg_loop_ref = NULL;
|
|||||||
static ImagePolicy *arg_image_policy = NULL;
|
static ImagePolicy *arg_image_policy = NULL;
|
||||||
static bool arg_mtree_hash = true;
|
static bool arg_mtree_hash = true;
|
||||||
static bool arg_via_service = false;
|
static bool arg_via_service = false;
|
||||||
|
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
|
||||||
|
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
||||||
@ -151,6 +152,8 @@ static int help(void) {
|
|||||||
" Generate JSON output\n"
|
" Generate JSON output\n"
|
||||||
" --loop-ref=NAME Set reference string for loopback device\n"
|
" --loop-ref=NAME Set reference string for loopback device\n"
|
||||||
" --mtree-hash=BOOL Whether to include SHA256 hash in the mtree output\n"
|
" --mtree-hash=BOOL Whether to include SHA256 hash in the mtree output\n"
|
||||||
|
" --user Discover user images\n"
|
||||||
|
" --system Discover system images\n"
|
||||||
"\n%3$sCommands:%4$s\n"
|
"\n%3$sCommands:%4$s\n"
|
||||||
" -h --help Show this help\n"
|
" -h --help Show this help\n"
|
||||||
" --version Show package version\n"
|
" --version Show package version\n"
|
||||||
@ -274,6 +277,8 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
ARG_VALIDATE,
|
ARG_VALIDATE,
|
||||||
ARG_MTREE_HASH,
|
ARG_MTREE_HASH,
|
||||||
ARG_MAKE_ARCHIVE,
|
ARG_MAKE_ARCHIVE,
|
||||||
|
ARG_SYSTEM,
|
||||||
|
ARG_USER,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
@ -307,10 +312,13 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
{ "validate", no_argument, NULL, ARG_VALIDATE },
|
{ "validate", no_argument, NULL, ARG_VALIDATE },
|
||||||
{ "mtree-hash", required_argument, NULL, ARG_MTREE_HASH },
|
{ "mtree-hash", required_argument, NULL, ARG_MTREE_HASH },
|
||||||
{ "make-archive", no_argument, NULL, ARG_MAKE_ARCHIVE },
|
{ "make-archive", no_argument, NULL, ARG_MAKE_ARCHIVE },
|
||||||
|
{ "system", no_argument, NULL, ARG_SYSTEM },
|
||||||
|
{ "user", no_argument, NULL, ARG_USER },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
_cleanup_free_ char **buf = NULL; /* we use free(), not strv_free() here, as we don't copy the strings here */
|
_cleanup_free_ char **buf = NULL; /* we use free(), not strv_free() here, as we don't copy the strings here */
|
||||||
|
bool system_scope_requested = false, user_scope_requested = false;
|
||||||
int c, r;
|
int c, r;
|
||||||
|
|
||||||
assert(argc >= 0);
|
assert(argc >= 0);
|
||||||
@ -531,7 +539,6 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ARG_MAKE_ARCHIVE:
|
case ARG_MAKE_ARCHIVE:
|
||||||
|
|
||||||
r = dlopen_libarchive();
|
r = dlopen_libarchive();
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Archive support not available (compiled without libarchive, or libarchive not installed?).");
|
return log_error_errno(r, "Archive support not available (compiled without libarchive, or libarchive not installed?).");
|
||||||
@ -539,6 +546,14 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
arg_action = ACTION_MAKE_ARCHIVE;
|
arg_action = ACTION_MAKE_ARCHIVE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_SYSTEM:
|
||||||
|
system_scope_requested = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ARG_USER:
|
||||||
|
user_scope_requested = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -547,6 +562,10 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (system_scope_requested || user_scope_requested)
|
||||||
|
arg_runtime_scope = system_scope_requested && user_scope_requested ? _RUNTIME_SCOPE_INVALID :
|
||||||
|
system_scope_requested ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER;
|
||||||
|
|
||||||
switch (arg_action) {
|
switch (arg_action) {
|
||||||
|
|
||||||
case ACTION_DISSECT:
|
case ACTION_DISSECT:
|
||||||
@ -1851,7 +1870,7 @@ static int action_discover(void) {
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
for (ImageClass cl = 0; cl < _IMAGE_CLASS_MAX; cl++) {
|
for (ImageClass cl = 0; cl < _IMAGE_CLASS_MAX; cl++) {
|
||||||
r = image_discover(cl, NULL, images);
|
r = image_discover(arg_runtime_scope, cl, NULL, images);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to discover images: %m");
|
return log_error_errno(r, "Failed to discover images: %m");
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN;
|
static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN;
|
||||||
static ImageClass arg_class = IMAGE_MACHINE;
|
static ImageClass arg_class = IMAGE_MACHINE;
|
||||||
|
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
|
||||||
|
|
||||||
static void determine_compression_from_filename(const char *p) {
|
static void determine_compression_from_filename(const char *p) {
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ static int export_tar(int argc, char *argv[], void *userdata) {
|
|||||||
|
|
||||||
local = argv[1];
|
local = argv[1];
|
||||||
if (image_name_is_valid(local)) {
|
if (image_name_is_valid(local)) {
|
||||||
r = image_find(arg_class, local, NULL, &image);
|
r = image_find(arg_runtime_scope, arg_class, local, NULL, &image);
|
||||||
if (r == -ENOENT)
|
if (r == -ENOENT)
|
||||||
return log_error_errno(r, "Image %s not found.", local);
|
return log_error_errno(r, "Image %s not found.", local);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -139,7 +140,7 @@ static int export_raw(int argc, char *argv[], void *userdata) {
|
|||||||
|
|
||||||
local = argv[1];
|
local = argv[1];
|
||||||
if (image_name_is_valid(local)) {
|
if (image_name_is_valid(local)) {
|
||||||
r = image_find(arg_class, local, NULL, &image);
|
r = image_find(arg_runtime_scope, arg_class, local, NULL, &image);
|
||||||
if (r == -ENOENT)
|
if (r == -ENOENT)
|
||||||
return log_error_errno(r, "Image %s not found.", local);
|
return log_error_errno(r, "Image %s not found.", local);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -34,6 +34,7 @@ static bool arg_sync = true;
|
|||||||
static bool arg_direct = false;
|
static bool arg_direct = false;
|
||||||
static const char *arg_image_root = NULL;
|
static const char *arg_image_root = NULL;
|
||||||
static ImageClass arg_class = IMAGE_MACHINE;
|
static ImageClass arg_class = IMAGE_MACHINE;
|
||||||
|
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
|
||||||
|
|
||||||
typedef struct ProgressInfo {
|
typedef struct ProgressInfo {
|
||||||
RateLimit limit;
|
RateLimit limit;
|
||||||
@ -145,7 +146,7 @@ static int import_fs(int argc, char *argv[], void *userdata) {
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
if (!arg_force) {
|
if (!arg_force) {
|
||||||
r = image_find(arg_class, local, NULL, NULL);
|
r = image_find(arg_runtime_scope, arg_class, local, NULL, NULL);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (r != -ENOENT)
|
if (r != -ENOENT)
|
||||||
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
|
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
|
||||||
|
@ -30,6 +30,7 @@ static const char *arg_image_root = NULL;
|
|||||||
static ImportFlags arg_import_flags = IMPORT_BTRFS_SUBVOL | IMPORT_BTRFS_QUOTA | IMPORT_CONVERT_QCOW2 | IMPORT_SYNC;
|
static ImportFlags arg_import_flags = IMPORT_BTRFS_SUBVOL | IMPORT_BTRFS_QUOTA | IMPORT_CONVERT_QCOW2 | IMPORT_SYNC;
|
||||||
static uint64_t arg_offset = UINT64_MAX, arg_size_max = UINT64_MAX;
|
static uint64_t arg_offset = UINT64_MAX, arg_size_max = UINT64_MAX;
|
||||||
static ImageClass arg_class = IMAGE_MACHINE;
|
static ImageClass arg_class = IMAGE_MACHINE;
|
||||||
|
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
|
||||||
|
|
||||||
static int normalize_local(const char *local, char **ret) {
|
static int normalize_local(const char *local, char **ret) {
|
||||||
_cleanup_free_ char *ll = NULL;
|
_cleanup_free_ char *ll = NULL;
|
||||||
@ -63,7 +64,7 @@ static int normalize_local(const char *local, char **ret) {
|
|||||||
local = "imported";
|
local = "imported";
|
||||||
|
|
||||||
if (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) {
|
if (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) {
|
||||||
r = image_find(arg_class, local, NULL, NULL);
|
r = image_find(arg_runtime_scope, arg_class, local, NULL, NULL);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (r != -ENOENT)
|
if (r != -ENOENT)
|
||||||
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
|
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
|
||||||
|
@ -111,6 +111,8 @@ struct Manager {
|
|||||||
|
|
||||||
bool use_btrfs_subvol;
|
bool use_btrfs_subvol;
|
||||||
bool use_btrfs_quota;
|
bool use_btrfs_quota;
|
||||||
|
|
||||||
|
RuntimeScope runtime_scope; /* for now: always RUNTIME_SCOPE_SYSTEM */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TRANSFERS_MAX 64
|
#define TRANSFERS_MAX 64
|
||||||
@ -721,6 +723,7 @@ static int manager_new(Manager **ret) {
|
|||||||
*m = (Manager) {
|
*m = (Manager) {
|
||||||
.use_btrfs_subvol = true,
|
.use_btrfs_subvol = true,
|
||||||
.use_btrfs_quota = true,
|
.use_btrfs_quota = true,
|
||||||
|
.runtime_scope = RUNTIME_SCOPE_SYSTEM,
|
||||||
};
|
};
|
||||||
|
|
||||||
r = sd_event_default(&m->event);
|
r = sd_event_default(&m->event);
|
||||||
@ -1332,6 +1335,7 @@ static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_er
|
|||||||
static int method_list_images(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
|
static int method_list_images(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
|
||||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||||
ImageClass class = _IMAGE_CLASS_INVALID;
|
ImageClass class = _IMAGE_CLASS_INVALID;
|
||||||
|
Manager *m = ASSERT_PTR(userdata);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(msg);
|
assert(msg);
|
||||||
@ -1372,7 +1376,7 @@ static int method_list_images(sd_bus_message *msg, void *userdata, sd_bus_error
|
|||||||
if (!h)
|
if (!h)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = image_discover(c, /* root= */ NULL, h);
|
r = image_discover(m->runtime_scope, c, /* root= */ NULL, h);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (class >= 0)
|
if (class >= 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -33,6 +33,7 @@ static ImportFlags arg_import_flags = IMPORT_PULL_SETTINGS | IMPORT_PULL_ROOTHAS
|
|||||||
static uint64_t arg_offset = UINT64_MAX, arg_size_max = UINT64_MAX;
|
static uint64_t arg_offset = UINT64_MAX, arg_size_max = UINT64_MAX;
|
||||||
static char *arg_checksum = NULL;
|
static char *arg_checksum = NULL;
|
||||||
static ImageClass arg_class = IMAGE_MACHINE;
|
static ImageClass arg_class = IMAGE_MACHINE;
|
||||||
|
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
|
||||||
|
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_checksum, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_checksum, freep);
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ static int normalize_local(const char *local, const char *url, char **ret) {
|
|||||||
local);
|
local);
|
||||||
|
|
||||||
if (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) {
|
if (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) {
|
||||||
r = image_find(arg_class, local, NULL, NULL);
|
r = image_find(arg_runtime_scope, arg_class, local, NULL, NULL);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (r != -ENOENT)
|
if (r != -ENOENT)
|
||||||
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
|
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
|
||||||
|
@ -178,7 +178,7 @@ int bus_image_method_clone(
|
|||||||
return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
|
return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
|
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
|
||||||
r = image_clone(image, new_name, read_only);
|
r = image_clone(image, new_name, read_only, m->runtime_scope);
|
||||||
report_errno_and_exit(errno_pipe_fd[1], r);
|
report_errno_and_exit(errno_pipe_fd[1], r);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,6 +402,7 @@ char* image_bus_path(const char *name) {
|
|||||||
static int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
|
static int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
|
||||||
_cleanup_hashmap_free_ Hashmap *images = NULL;
|
_cleanup_hashmap_free_ Hashmap *images = NULL;
|
||||||
_cleanup_strv_free_ char **l = NULL;
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
|
Manager *m = ASSERT_PTR(userdata);
|
||||||
Image *image;
|
Image *image;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -413,7 +414,7 @@ static int image_node_enumerator(sd_bus *bus, const char *path, void *userdata,
|
|||||||
if (!images)
|
if (!images)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = image_discover(IMAGE_MACHINE, NULL, images);
|
r = image_discover(m->runtime_scope, IMAGE_MACHINE, NULL, images);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ int vl_method_clone_image(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
|||||||
return log_debug_errno(r, "Failed to fork: %m");
|
return log_debug_errno(r, "Failed to fork: %m");
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
|
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
|
||||||
r = image_clone(image, p.new_name, p.read_only > 0);
|
r = image_clone(image, p.new_name, p.read_only > 0, manager->runtime_scope);
|
||||||
report_errno_and_exit(errno_pipe_fd[1], r);
|
report_errno_and_exit(errno_pipe_fd[1], r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,7 +440,7 @@ int manager_acquire_image(Manager *m, const char *name, Image **ret) {
|
|||||||
return log_debug_errno(r, "Failed to enable source: %m") ;
|
return log_debug_errno(r, "Failed to enable source: %m") ;
|
||||||
|
|
||||||
_cleanup_(image_unrefp) Image *image = NULL;
|
_cleanup_(image_unrefp) Image *image = NULL;
|
||||||
r = image_find(IMAGE_MACHINE, name, NULL, &image);
|
r = image_find(m->runtime_scope, IMAGE_MACHINE, name, NULL, &image);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to find image: %m");
|
return log_debug_errno(r, "Failed to find image: %m");
|
||||||
|
|
||||||
@ -467,7 +467,7 @@ int rename_image_and_update_cache(Manager *m, Image *image, const char* new_name
|
|||||||
/* The image is cached with its name, hence it is necessary to remove from the cache before renaming. */
|
/* The image is cached with its name, hence it is necessary to remove from the cache before renaming. */
|
||||||
assert_se(hashmap_remove_value(m->image_cache, image->name, image));
|
assert_se(hashmap_remove_value(m->image_cache, image->name, image));
|
||||||
|
|
||||||
r = image_rename(image, new_name);
|
r = image_rename(image, new_name, m->runtime_scope);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
image = image_unref(image);
|
image = image_unref(image);
|
||||||
return r;
|
return r;
|
||||||
|
@ -123,7 +123,7 @@ static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_erro
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = image_find(IMAGE_MACHINE, name, NULL, NULL);
|
r = image_find(m->runtime_scope, IMAGE_MACHINE, name, NULL, NULL);
|
||||||
if (r == -ENOENT)
|
if (r == -ENOENT)
|
||||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
|
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -476,7 +476,7 @@ static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_er
|
|||||||
if (!images)
|
if (!images)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = image_discover(IMAGE_MACHINE, NULL, images);
|
r = image_discover(m->runtime_scope, IMAGE_MACHINE, NULL, images);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -753,7 +753,7 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err
|
|||||||
goto child_fail;
|
goto child_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = image_discover(IMAGE_MACHINE, NULL, images);
|
r = image_discover(m->runtime_scope, IMAGE_MACHINE, NULL, images);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto child_fail;
|
goto child_fail;
|
||||||
|
|
||||||
|
@ -641,6 +641,7 @@ static int list_image_one_and_maybe_read_metadata(sd_varlink *link, Image *image
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||||
|
Manager *m = ASSERT_PTR(userdata);
|
||||||
struct params {
|
struct params {
|
||||||
const char *image_name;
|
const char *image_name;
|
||||||
AcquireMetadata acquire_metadata;
|
AcquireMetadata acquire_metadata;
|
||||||
@ -667,7 +668,7 @@ static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters,
|
|||||||
if (!image_name_is_valid(p.image_name))
|
if (!image_name_is_valid(p.image_name))
|
||||||
return sd_varlink_error_invalid_parameter_name(link, "name");
|
return sd_varlink_error_invalid_parameter_name(link, "name");
|
||||||
|
|
||||||
r = image_find(IMAGE_MACHINE, p.image_name, /* root = */ NULL, &found);
|
r = image_find(m->runtime_scope, IMAGE_MACHINE, p.image_name, /* root = */ NULL, &found);
|
||||||
if (r == -ENOENT)
|
if (r == -ENOENT)
|
||||||
return sd_varlink_error(link, "io.systemd.MachineImage.NoSuchImage", NULL);
|
return sd_varlink_error(link, "io.systemd.MachineImage.NoSuchImage", NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -683,7 +684,7 @@ static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters,
|
|||||||
if (!images)
|
if (!images)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = image_discover(IMAGE_MACHINE, /* root = */ NULL, images);
|
r = image_discover(m->runtime_scope, IMAGE_MACHINE, /* root = */ NULL, images);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to discover images: %m");
|
return log_debug_errno(r, "Failed to discover images: %m");
|
||||||
|
|
||||||
|
@ -40,10 +40,14 @@ static int manager_new(Manager **ret) {
|
|||||||
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
m = new0(Manager, 1);
|
m = new(Manager, 1);
|
||||||
if (!m)
|
if (!m)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*m = (Manager) {
|
||||||
|
.runtime_scope = RUNTIME_SCOPE_SYSTEM,
|
||||||
|
};
|
||||||
|
|
||||||
m->machines = hashmap_new(&machine_hash_ops);
|
m->machines = hashmap_new(&machine_hash_ops);
|
||||||
if (!m->machines)
|
if (!m->machines)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -42,6 +42,8 @@ struct Manager {
|
|||||||
|
|
||||||
sd_varlink_server *varlink_userdb_server;
|
sd_varlink_server *varlink_userdb_server;
|
||||||
sd_varlink_server *varlink_machine_server;
|
sd_varlink_server *varlink_machine_server;
|
||||||
|
|
||||||
|
RuntimeScope runtime_scope; /* for now: always RUNTIME_SCOPE_SYSTEM */
|
||||||
};
|
};
|
||||||
|
|
||||||
int manager_add_machine(Manager *m, const char *name, Machine **ret);
|
int manager_add_machine(Manager *m, const char *name, Machine **ret);
|
||||||
|
@ -3167,7 +3167,8 @@ static int determine_names(void) {
|
|||||||
if (arg_machine) {
|
if (arg_machine) {
|
||||||
_cleanup_(image_unrefp) Image *i = NULL;
|
_cleanup_(image_unrefp) Image *i = NULL;
|
||||||
|
|
||||||
r = image_find(IMAGE_MACHINE, arg_machine, NULL, &i);
|
r = image_find(arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
|
||||||
|
IMAGE_MACHINE, arg_machine, NULL, &i);
|
||||||
if (r == -ENOENT)
|
if (r == -ENOENT)
|
||||||
return log_error_errno(r, "No image for machine '%s'.", arg_machine);
|
return log_error_errno(r, "No image for machine '%s'.", arg_machine);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -173,6 +173,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(portable_metadata_hash_ops, char,
|
|||||||
PortableMetadata, portable_metadata_unref);
|
PortableMetadata, portable_metadata_unref);
|
||||||
|
|
||||||
static int extract_now(
|
static int extract_now(
|
||||||
|
RuntimeScope scope,
|
||||||
const char *where,
|
const char *where,
|
||||||
char **matches,
|
char **matches,
|
||||||
const char *image_name,
|
const char *image_name,
|
||||||
@ -199,6 +200,7 @@ static int extract_now(
|
|||||||
* parent. To handle both cases in one call this function also gets a 'socket_fd' parameter, which when >= 0 is
|
* parent. To handle both cases in one call this function also gets a 'socket_fd' parameter, which when >= 0 is
|
||||||
* used to send the data to the parent. */
|
* used to send the data to the parent. */
|
||||||
|
|
||||||
|
assert(scope < _RUNTIME_SCOPE_MAX);
|
||||||
assert(where);
|
assert(where);
|
||||||
|
|
||||||
/* First, find os-release/extension-release and send it upstream (or just save it). */
|
/* First, find os-release/extension-release and send it upstream (or just save it). */
|
||||||
@ -248,7 +250,7 @@ static int extract_now(
|
|||||||
/* Then, send unit file data to the parent (or/and add it to the hashmap). For that we use our usual unit
|
/* Then, send unit file data to the parent (or/and add it to the hashmap). For that we use our usual unit
|
||||||
* discovery logic. Note that we force looking inside of /lib/systemd/system/ for units too, as the
|
* discovery logic. Note that we force looking inside of /lib/systemd/system/ for units too, as the
|
||||||
* image might have a legacy split-usr layout. */
|
* image might have a legacy split-usr layout. */
|
||||||
r = lookup_paths_init(&paths, RUNTIME_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, where);
|
r = lookup_paths_init(&paths, scope, LOOKUP_PATHS_SPLIT_USR, where);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to acquire lookup paths: %m");
|
return log_debug_errno(r, "Failed to acquire lookup paths: %m");
|
||||||
|
|
||||||
@ -348,6 +350,7 @@ static int extract_now(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int portable_extract_by_path(
|
static int portable_extract_by_path(
|
||||||
|
RuntimeScope scope,
|
||||||
const char *path,
|
const char *path,
|
||||||
bool path_is_extension,
|
bool path_is_extension,
|
||||||
bool relax_extension_release_check,
|
bool relax_extension_release_check,
|
||||||
@ -381,7 +384,7 @@ static int portable_extract_by_path(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to extract image name from path '%s': %m", path);
|
return log_error_errno(r, "Failed to extract image name from path '%s': %m", path);
|
||||||
|
|
||||||
r = extract_now(path, matches, image_name, path_is_extension, /* relax_extension_release_check= */ false, -1, &os_release, &unit_files);
|
r = extract_now(scope, path, matches, image_name, path_is_extension, /* relax_extension_release_check= */ false, -1, &os_release, &unit_files);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -458,7 +461,7 @@ static int portable_extract_by_path(
|
|||||||
goto child_finish;
|
goto child_finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = extract_now(tmpdir, matches, m->image_name, path_is_extension, relax_extension_release_check, seq[1], NULL, NULL);
|
r = extract_now(scope, tmpdir, matches, m->image_name, path_is_extension, relax_extension_release_check, seq[1], NULL, NULL);
|
||||||
|
|
||||||
child_finish:
|
child_finish:
|
||||||
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
|
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||||
@ -549,6 +552,7 @@ static int portable_extract_by_path(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int extract_image_and_extensions(
|
static int extract_image_and_extensions(
|
||||||
|
RuntimeScope scope,
|
||||||
const char *name_or_path,
|
const char *name_or_path,
|
||||||
char **matches,
|
char **matches,
|
||||||
char **extension_image_paths,
|
char **extension_image_paths,
|
||||||
@ -595,7 +599,7 @@ static int extract_image_and_extensions(
|
|||||||
name_or_path = result.path;
|
name_or_path = result.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = image_find_harder(IMAGE_PORTABLE, name_or_path, /* root= */ NULL, &image);
|
r = image_find_harder(scope, IMAGE_PORTABLE, name_or_path, /* root= */ NULL, &image);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -633,7 +637,7 @@ static int extract_image_and_extensions(
|
|||||||
path = ext_result.path;
|
path = ext_result.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = image_find_harder(IMAGE_PORTABLE, path, NULL, &new);
|
r = image_find_harder(scope, IMAGE_PORTABLE, path, NULL, &new);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -645,6 +649,7 @@ static int extract_image_and_extensions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
r = portable_extract_by_path(
|
r = portable_extract_by_path(
|
||||||
|
scope,
|
||||||
image->path,
|
image->path,
|
||||||
/* path_is_extension= */ false,
|
/* path_is_extension= */ false,
|
||||||
/* relax_extension_release_check= */ false,
|
/* relax_extension_release_check= */ false,
|
||||||
@ -687,6 +692,7 @@ static int extract_image_and_extensions(
|
|||||||
const char *e;
|
const char *e;
|
||||||
|
|
||||||
r = portable_extract_by_path(
|
r = portable_extract_by_path(
|
||||||
|
scope,
|
||||||
ext->path,
|
ext->path,
|
||||||
/* path_is_extension= */ true,
|
/* path_is_extension= */ true,
|
||||||
relax_extension_release_check,
|
relax_extension_release_check,
|
||||||
@ -754,6 +760,7 @@ static int extract_image_and_extensions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
int portable_extract(
|
int portable_extract(
|
||||||
|
RuntimeScope scope,
|
||||||
const char *name_or_path,
|
const char *name_or_path,
|
||||||
char **matches,
|
char **matches,
|
||||||
char **extension_image_paths,
|
char **extension_image_paths,
|
||||||
@ -775,6 +782,7 @@ int portable_extract(
|
|||||||
assert(name_or_path);
|
assert(name_or_path);
|
||||||
|
|
||||||
r = extract_image_and_extensions(
|
r = extract_image_and_extensions(
|
||||||
|
scope,
|
||||||
name_or_path,
|
name_or_path,
|
||||||
matches,
|
matches,
|
||||||
extension_image_paths,
|
extension_image_paths,
|
||||||
@ -1426,6 +1434,7 @@ static int image_target_path(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int install_image(
|
static int install_image(
|
||||||
|
RuntimeScope scope,
|
||||||
const char *image_path,
|
const char *image_path,
|
||||||
PortableFlags flags,
|
PortableFlags flags,
|
||||||
PortableChange **changes,
|
PortableChange **changes,
|
||||||
@ -1434,13 +1443,14 @@ static int install_image(
|
|||||||
_cleanup_free_ char *target = NULL;
|
_cleanup_free_ char *target = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
assert(scope < _RUNTIME_SCOPE_MAX);
|
||||||
assert(image_path);
|
assert(image_path);
|
||||||
|
|
||||||
/* If the image is outside of the image search also link it into it, so that it can be found with
|
/* If the image is outside of the image search also link it into it, so that it can be found with
|
||||||
* short image names and is listed among the images. If we are operating in mixed mode, the image is
|
* short image names and is listed among the images. If we are operating in mixed mode, the image is
|
||||||
* copied instead. */
|
* copied instead. */
|
||||||
|
|
||||||
if (image_in_search_path(IMAGE_PORTABLE, NULL, image_path))
|
if (image_in_search_path(scope, IMAGE_PORTABLE, NULL, image_path))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = image_target_path(image_path, flags, &target);
|
r = image_target_path(image_path, flags, &target);
|
||||||
@ -1485,6 +1495,7 @@ static int install_image(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int install_image_and_extensions(
|
static int install_image_and_extensions(
|
||||||
|
RuntimeScope scope,
|
||||||
const Image *image,
|
const Image *image,
|
||||||
OrderedHashmap *extension_images,
|
OrderedHashmap *extension_images,
|
||||||
PortableFlags flags,
|
PortableFlags flags,
|
||||||
@ -1497,12 +1508,12 @@ static int install_image_and_extensions(
|
|||||||
assert(image);
|
assert(image);
|
||||||
|
|
||||||
ORDERED_HASHMAP_FOREACH(ext, extension_images) {
|
ORDERED_HASHMAP_FOREACH(ext, extension_images) {
|
||||||
r = install_image(ext->path, flags, changes, n_changes);
|
r = install_image(scope, ext->path, flags, changes, n_changes);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = install_image(image->path, flags, changes, n_changes);
|
r = install_image(scope, image->path, flags, changes, n_changes);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -1595,6 +1606,7 @@ static void log_portable_verb(
|
|||||||
}
|
}
|
||||||
|
|
||||||
int portable_attach(
|
int portable_attach(
|
||||||
|
RuntimeScope scope,
|
||||||
sd_bus *bus,
|
sd_bus *bus,
|
||||||
const char *name_or_path,
|
const char *name_or_path,
|
||||||
char **matches,
|
char **matches,
|
||||||
@ -1615,7 +1627,10 @@ int portable_attach(
|
|||||||
PortableMetadata *item;
|
PortableMetadata *item;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
assert(scope < _RUNTIME_SCOPE_MAX);
|
||||||
|
|
||||||
r = extract_image_and_extensions(
|
r = extract_image_and_extensions(
|
||||||
|
scope,
|
||||||
name_or_path,
|
name_or_path,
|
||||||
matches,
|
matches,
|
||||||
extension_image_paths,
|
extension_image_paths,
|
||||||
@ -1672,13 +1687,13 @@ int portable_attach(
|
|||||||
strempty(extensions_joined));
|
strempty(extensions_joined));
|
||||||
}
|
}
|
||||||
|
|
||||||
r = lookup_paths_init(&paths, RUNTIME_SCOPE_SYSTEM, /* flags= */ 0, NULL);
|
r = lookup_paths_init(&paths, scope, /* flags= */ 0, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!FLAGS_SET(flags, PORTABLE_REATTACH) && !FLAGS_SET(flags, PORTABLE_FORCE_ATTACH))
|
if (!FLAGS_SET(flags, PORTABLE_REATTACH) && !FLAGS_SET(flags, PORTABLE_FORCE_ATTACH))
|
||||||
HASHMAP_FOREACH(item, unit_files) {
|
HASHMAP_FOREACH(item, unit_files) {
|
||||||
r = unit_file_exists(RUNTIME_SCOPE_SYSTEM, &paths, item->name);
|
r = unit_file_exists(scope, &paths, item->name);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return sd_bus_error_set_errnof(error, r, "Failed to determine whether unit '%s' exists on the host: %m", item->name);
|
return sd_bus_error_set_errnof(error, r, "Failed to determine whether unit '%s' exists on the host: %m", item->name);
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
@ -1700,7 +1715,7 @@ int portable_attach(
|
|||||||
|
|
||||||
/* We don't care too much for the image symlink/copy, it's just a convenience thing, it's not necessary for
|
/* We don't care too much for the image symlink/copy, it's just a convenience thing, it's not necessary for
|
||||||
* proper operation otherwise. */
|
* proper operation otherwise. */
|
||||||
(void) install_image_and_extensions(image, extension_images, flags, changes, n_changes);
|
(void) install_image_and_extensions(scope, image, extension_images, flags, changes, n_changes);
|
||||||
|
|
||||||
log_portable_verb(
|
log_portable_verb(
|
||||||
"attached",
|
"attached",
|
||||||
@ -1844,6 +1859,7 @@ static int test_chroot_dropin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
int portable_detach(
|
int portable_detach(
|
||||||
|
RuntimeScope scope,
|
||||||
sd_bus *bus,
|
sd_bus *bus,
|
||||||
const char *name_or_path,
|
const char *name_or_path,
|
||||||
char **extension_image_paths,
|
char **extension_image_paths,
|
||||||
@ -1857,12 +1873,12 @@ int portable_detach(
|
|||||||
_cleanup_free_ char *extensions = NULL;
|
_cleanup_free_ char *extensions = NULL;
|
||||||
_cleanup_closedir_ DIR *d = NULL;
|
_cleanup_closedir_ DIR *d = NULL;
|
||||||
const char *where, *item;
|
const char *where, *item;
|
||||||
int ret = 0;
|
int r, ret = 0;
|
||||||
int r;
|
|
||||||
|
|
||||||
|
assert(scope < _RUNTIME_SCOPE_MAX);
|
||||||
assert(name_or_path);
|
assert(name_or_path);
|
||||||
|
|
||||||
r = lookup_paths_init(&paths, RUNTIME_SCOPE_SYSTEM, /* flags= */ 0, NULL);
|
r = lookup_paths_init(&paths, scope, /* flags= */ 0, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -1930,7 +1946,7 @@ int portable_detach(
|
|||||||
if (r == 0)
|
if (r == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (path_is_absolute(image) && !image_in_search_path(IMAGE_PORTABLE, NULL, image)) {
|
if (path_is_absolute(image) && !image_in_search_path(scope, IMAGE_PORTABLE, NULL, image)) {
|
||||||
r = set_ensure_consume(&markers, &path_hash_ops_free, TAKE_PTR(image));
|
r = set_ensure_consume(&markers, &path_hash_ops_free, TAKE_PTR(image));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -2031,6 +2047,7 @@ not_found:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int portable_get_state_internal(
|
static int portable_get_state_internal(
|
||||||
|
RuntimeScope scope,
|
||||||
sd_bus *bus,
|
sd_bus *bus,
|
||||||
const char *name_or_path,
|
const char *name_or_path,
|
||||||
char **extension_image_paths,
|
char **extension_image_paths,
|
||||||
@ -2045,10 +2062,11 @@ static int portable_get_state_internal(
|
|||||||
const char *where;
|
const char *where;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
assert(scope < _RUNTIME_SCOPE_MAX);
|
||||||
assert(name_or_path);
|
assert(name_or_path);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
r = lookup_paths_init(&paths, RUNTIME_SCOPE_SYSTEM, /* flags= */ 0, NULL);
|
r = lookup_paths_init(&paths, scope, /* flags= */ 0, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -2084,7 +2102,7 @@ static int portable_get_state_internal(
|
|||||||
if (r == 0)
|
if (r == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = unit_file_lookup_state(RUNTIME_SCOPE_SYSTEM, &paths, de->d_name, &state);
|
r = unit_file_lookup_state(scope, &paths, de->d_name, &state);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to determine unit file state of '%s': %m", de->d_name);
|
return log_debug_errno(r, "Failed to determine unit file state of '%s': %m", de->d_name);
|
||||||
if (!IN_SET(state, UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED, UNIT_FILE_LINKED_RUNTIME))
|
if (!IN_SET(state, UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED, UNIT_FILE_LINKED_RUNTIME))
|
||||||
@ -2109,6 +2127,7 @@ static int portable_get_state_internal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
int portable_get_state(
|
int portable_get_state(
|
||||||
|
RuntimeScope scope,
|
||||||
sd_bus *bus,
|
sd_bus *bus,
|
||||||
const char *name_or_path,
|
const char *name_or_path,
|
||||||
char **extension_image_paths,
|
char **extension_image_paths,
|
||||||
@ -2125,12 +2144,19 @@ int portable_get_state(
|
|||||||
/* We look for matching units twice: once in the regular directories, and once in the runtime directories — but
|
/* We look for matching units twice: once in the regular directories, and once in the runtime directories — but
|
||||||
* the latter only if we didn't find anything in the former. */
|
* the latter only if we didn't find anything in the former. */
|
||||||
|
|
||||||
r = portable_get_state_internal(bus, name_or_path, extension_image_paths, flags & ~PORTABLE_RUNTIME, &state, error);
|
r = portable_get_state_internal(
|
||||||
|
scope,
|
||||||
|
bus,
|
||||||
|
name_or_path,
|
||||||
|
extension_image_paths,
|
||||||
|
flags & ~PORTABLE_RUNTIME,
|
||||||
|
&state,
|
||||||
|
error);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (state == PORTABLE_DETACHED) {
|
if (state == PORTABLE_DETACHED) {
|
||||||
r = portable_get_state_internal(bus, name_or_path, extension_image_paths, flags | PORTABLE_RUNTIME, &state, error);
|
r = portable_get_state_internal(scope, bus, name_or_path, extension_image_paths, flags | PORTABLE_RUNTIME, &state, error);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "dissect-image.h"
|
#include "dissect-image.h"
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "runtime-scope.h"
|
||||||
#include "set.h"
|
#include "set.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
|
||||||
@ -69,12 +70,12 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(PortableMetadata*, portable_metadata_unref);
|
|||||||
|
|
||||||
int portable_metadata_hashmap_to_sorted_array(Hashmap *unit_files, PortableMetadata ***ret);
|
int portable_metadata_hashmap_to_sorted_array(Hashmap *unit_files, PortableMetadata ***ret);
|
||||||
|
|
||||||
int portable_extract(const char *image, char **matches, char **extension_image_paths, const ImagePolicy *image_policy, PortableFlags flags, PortableMetadata **ret_os_release, OrderedHashmap **ret_extension_releases, Hashmap **ret_unit_files, char ***ret_valid_prefixes, sd_bus_error *error);
|
int portable_extract(RuntimeScope scope, const char *image, char **matches, char **extension_image_paths, const ImagePolicy *image_policy, PortableFlags flags, PortableMetadata **ret_os_release, OrderedHashmap **ret_extension_releases, Hashmap **ret_unit_files, char ***ret_valid_prefixes, sd_bus_error *error);
|
||||||
|
|
||||||
int portable_attach(sd_bus *bus, const char *name_or_path, char **matches, const char *profile, char **extension_images, const ImagePolicy* image_policy, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error);
|
int portable_attach(RuntimeScope scope, sd_bus *bus, const char *name_or_path, char **matches, const char *profile, char **extension_images, const ImagePolicy* image_policy, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error);
|
||||||
int portable_detach(sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error);
|
int portable_detach(RuntimeScope scope, sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error);
|
||||||
|
|
||||||
int portable_get_state(sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableState *ret, sd_bus_error *error);
|
int portable_get_state(RuntimeScope scope, sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableState *ret, sd_bus_error *error);
|
||||||
|
|
||||||
int portable_get_profiles(char ***ret);
|
int portable_get_profiles(char ***ret);
|
||||||
|
|
||||||
|
@ -165,6 +165,7 @@ static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_er
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = portable_get_state(
|
r = portable_get_state(
|
||||||
|
m->runtime_scope,
|
||||||
sd_bus_message_get_bus(message),
|
sd_bus_message_get_bus(message),
|
||||||
image->path,
|
image->path,
|
||||||
NULL,
|
NULL,
|
||||||
@ -225,6 +226,7 @@ static int method_get_image_metadata(sd_bus_message *message, void *userdata, sd
|
|||||||
|
|
||||||
static int method_get_image_state(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
static int method_get_image_state(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||||
_cleanup_strv_free_ char **extension_images = NULL;
|
_cleanup_strv_free_ char **extension_images = NULL;
|
||||||
|
Manager *m = ASSERT_PTR(userdata);
|
||||||
const char *name_or_path;
|
const char *name_or_path;
|
||||||
PortableState state;
|
PortableState state;
|
||||||
int r;
|
int r;
|
||||||
@ -254,6 +256,7 @@ static int method_get_image_state(sd_bus_message *message, void *userdata, sd_bu
|
|||||||
}
|
}
|
||||||
|
|
||||||
r = portable_get_state(
|
r = portable_get_state(
|
||||||
|
m->runtime_scope,
|
||||||
sd_bus_message_get_bus(message),
|
sd_bus_message_get_bus(message),
|
||||||
name_or_path,
|
name_or_path,
|
||||||
extension_images,
|
extension_images,
|
||||||
@ -330,6 +333,7 @@ static int method_detach_image(sd_bus_message *message, void *userdata, sd_bus_e
|
|||||||
return 1; /* Will call us back */
|
return 1; /* Will call us back */
|
||||||
|
|
||||||
r = portable_detach(
|
r = portable_detach(
|
||||||
|
m->runtime_scope,
|
||||||
sd_bus_message_get_bus(message),
|
sd_bus_message_get_bus(message),
|
||||||
name_or_path,
|
name_or_path,
|
||||||
extension_images,
|
extension_images,
|
||||||
|
@ -114,10 +114,8 @@ int bus_image_common_get_metadata(
|
|||||||
assert(name_or_path || image);
|
assert(name_or_path || image);
|
||||||
assert(message);
|
assert(message);
|
||||||
|
|
||||||
if (!m) {
|
if (!m)
|
||||||
assert(image);
|
m = ASSERT_PTR(ASSERT_PTR(image)->userdata);
|
||||||
m = image->userdata;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool have_exti = sd_bus_message_is_method_call(message, NULL, "GetImageMetadataWithExtensions") ||
|
bool have_exti = sd_bus_message_is_method_call(message, NULL, "GetImageMetadataWithExtensions") ||
|
||||||
sd_bus_message_is_method_call(message, NULL, "GetMetadataWithExtensions");
|
sd_bus_message_is_method_call(message, NULL, "GetMetadataWithExtensions");
|
||||||
@ -160,6 +158,7 @@ int bus_image_common_get_metadata(
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
r = portable_extract(
|
r = portable_extract(
|
||||||
|
m->runtime_scope,
|
||||||
image->path,
|
image->path,
|
||||||
matches,
|
matches,
|
||||||
extension_images,
|
extension_images,
|
||||||
@ -264,6 +263,7 @@ static int bus_image_method_get_state(
|
|||||||
|
|
||||||
_cleanup_strv_free_ char **extension_images = NULL;
|
_cleanup_strv_free_ char **extension_images = NULL;
|
||||||
Image *image = ASSERT_PTR(userdata);
|
Image *image = ASSERT_PTR(userdata);
|
||||||
|
Manager *m = ASSERT_PTR(image->userdata);
|
||||||
PortableState state;
|
PortableState state;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -288,6 +288,7 @@ static int bus_image_method_get_state(
|
|||||||
}
|
}
|
||||||
|
|
||||||
r = portable_get_state(
|
r = portable_get_state(
|
||||||
|
m->runtime_scope,
|
||||||
sd_bus_message_get_bus(message),
|
sd_bus_message_get_bus(message),
|
||||||
image->path,
|
image->path,
|
||||||
extension_images,
|
extension_images,
|
||||||
@ -385,6 +386,7 @@ int bus_image_common_attach(
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
r = portable_attach(
|
r = portable_attach(
|
||||||
|
m->runtime_scope,
|
||||||
sd_bus_message_get_bus(message),
|
sd_bus_message_get_bus(message),
|
||||||
image->path,
|
image->path,
|
||||||
matches,
|
matches,
|
||||||
@ -463,6 +465,7 @@ static int bus_image_method_detach(
|
|||||||
return 1; /* Will call us back */
|
return 1; /* Will call us back */
|
||||||
|
|
||||||
r = portable_detach(
|
r = portable_detach(
|
||||||
|
m->runtime_scope,
|
||||||
sd_bus_message_get_bus(message),
|
sd_bus_message_get_bus(message),
|
||||||
image->path,
|
image->path,
|
||||||
extension_images,
|
extension_images,
|
||||||
@ -513,6 +516,7 @@ int bus_image_common_remove(
|
|||||||
return 1; /* Will call us back */
|
return 1; /* Will call us back */
|
||||||
|
|
||||||
r = portable_get_state(
|
r = portable_get_state(
|
||||||
|
m->runtime_scope,
|
||||||
sd_bus_message_get_bus(message),
|
sd_bus_message_get_bus(message),
|
||||||
image->path,
|
image->path,
|
||||||
NULL,
|
NULL,
|
||||||
@ -716,6 +720,7 @@ int bus_image_common_reattach(
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
r = portable_detach(
|
r = portable_detach(
|
||||||
|
m->runtime_scope,
|
||||||
sd_bus_message_get_bus(message),
|
sd_bus_message_get_bus(message),
|
||||||
image->path,
|
image->path,
|
||||||
extension_images,
|
extension_images,
|
||||||
@ -727,6 +732,7 @@ int bus_image_common_reattach(
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = portable_attach(
|
r = portable_attach(
|
||||||
|
m->runtime_scope,
|
||||||
sd_bus_message_get_bus(message),
|
sd_bus_message_get_bus(message),
|
||||||
image->path,
|
image->path,
|
||||||
matches,
|
matches,
|
||||||
@ -1039,7 +1045,7 @@ int bus_image_acquire(
|
|||||||
if (image_name_is_valid(name_or_path)) {
|
if (image_name_is_valid(name_or_path)) {
|
||||||
|
|
||||||
/* If it's a short name, let's search for it */
|
/* If it's a short name, let's search for it */
|
||||||
r = image_find(IMAGE_PORTABLE, name_or_path, NULL, &loaded);
|
r = image_find(m->runtime_scope, IMAGE_PORTABLE, name_or_path, NULL, &loaded);
|
||||||
if (r == -ENOENT)
|
if (r == -ENOENT)
|
||||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PORTABLE_IMAGE,
|
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PORTABLE_IMAGE,
|
||||||
"No image '%s' found.", name_or_path);
|
"No image '%s' found.", name_or_path);
|
||||||
|
@ -91,7 +91,7 @@ int manager_image_cache_discover(Manager *m, Hashmap *images, sd_bus_error *erro
|
|||||||
/* A wrapper around image_discover() (for finding images in search path) and portable_discover_attached() (for
|
/* A wrapper around image_discover() (for finding images in search path) and portable_discover_attached() (for
|
||||||
* finding attached images). */
|
* finding attached images). */
|
||||||
|
|
||||||
r = image_discover(IMAGE_PORTABLE, NULL, images);
|
r = image_discover(m->runtime_scope, IMAGE_PORTABLE, NULL, images);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -28,10 +28,14 @@ static int manager_new(Manager **ret) {
|
|||||||
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
m = new0(Manager, 1);
|
m = new(Manager, 1);
|
||||||
if (!m)
|
if (!m)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*m = (Manager) {
|
||||||
|
.runtime_scope = RUNTIME_SCOPE_SYSTEM,
|
||||||
|
};
|
||||||
|
|
||||||
r = sd_event_default(&m->event);
|
r = sd_event_default(&m->event);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "bus-object.h"
|
#include "bus-object.h"
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
#include "runtime-scope.h"
|
||||||
|
|
||||||
typedef struct Manager Manager;
|
typedef struct Manager Manager;
|
||||||
|
|
||||||
@ -23,6 +24,8 @@ struct Manager {
|
|||||||
|
|
||||||
LIST_HEAD(Operation, operations);
|
LIST_HEAD(Operation, operations);
|
||||||
unsigned n_operations;
|
unsigned n_operations;
|
||||||
|
|
||||||
|
RuntimeScope runtime_scope; /* for now always RUNTIME_SCOPE_SYSTEM */
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const BusObjectImplementation manager_object;
|
extern const BusObjectImplementation manager_object;
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "sd-path.h"
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "blockdev-util.h"
|
#include "blockdev-util.h"
|
||||||
#include "btrfs-util.h"
|
#include "btrfs-util.h"
|
||||||
@ -553,12 +555,95 @@ static int image_make(
|
|||||||
return -EMEDIUMTYPE;
|
return -EMEDIUMTYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *pick_image_search_path(ImageClass class) {
|
static int pick_image_search_path(
|
||||||
if (class < 0 || class >= _IMAGE_CLASS_MAX)
|
RuntimeScope scope,
|
||||||
return NULL;
|
ImageClass class,
|
||||||
|
char ***ret) {
|
||||||
|
|
||||||
/* Use the initrd search path if there is one, otherwise use the common one */
|
int r;
|
||||||
return in_initrd() && image_search_path_initrd[class] ? image_search_path_initrd[class] : image_search_path[class];
|
|
||||||
|
assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL);
|
||||||
|
assert(class < _IMAGE_CLASS_MAX);
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
if (class < 0) {
|
||||||
|
*ret = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scope < 0) {
|
||||||
|
_cleanup_strv_free_ char **a = NULL, **b = NULL;
|
||||||
|
|
||||||
|
r = pick_image_search_path(RUNTIME_SCOPE_USER, class, &a);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = pick_image_search_path(RUNTIME_SCOPE_SYSTEM, class, &b);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = strv_extend_strv(&a, b, /* filter_duplicates= */ false);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
*ret = TAKE_PTR(a);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (scope) {
|
||||||
|
|
||||||
|
case RUNTIME_SCOPE_SYSTEM: {
|
||||||
|
const char *ns;
|
||||||
|
/* Use the initrd search path if there is one, otherwise use the common one */
|
||||||
|
ns = in_initrd() && image_search_path_initrd[class] ?
|
||||||
|
image_search_path_initrd[class] :
|
||||||
|
image_search_path[class];
|
||||||
|
if (!ns)
|
||||||
|
break;
|
||||||
|
|
||||||
|
_cleanup_strv_free_ char **search = strv_split_nulstr(ns);
|
||||||
|
if (!search)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*ret = TAKE_PTR(search);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RUNTIME_SCOPE_USER: {
|
||||||
|
if (class != IMAGE_MACHINE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
static const uint64_t dirs[] = {
|
||||||
|
SD_PATH_USER_RUNTIME,
|
||||||
|
SD_PATH_USER_STATE_PRIVATE,
|
||||||
|
SD_PATH_USER_LIBRARY_PRIVATE,
|
||||||
|
};
|
||||||
|
|
||||||
|
_cleanup_strv_free_ char **search = NULL;
|
||||||
|
FOREACH_ELEMENT(d, dirs) {
|
||||||
|
_cleanup_free_ char *p = NULL;
|
||||||
|
|
||||||
|
r = sd_path_lookup(*d, "machines", &p);
|
||||||
|
if (r == -ENXIO) /* No XDG_RUNTIME_DIR set */
|
||||||
|
continue;
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = strv_consume(&search, TAKE_PTR(p));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ret = TAKE_PTR(search);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
*ret = NULL;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char **make_possible_filenames(ImageClass class, const char *image_name) {
|
static char **make_possible_filenames(ImageClass class, const char *image_name) {
|
||||||
@ -592,7 +677,8 @@ static char **make_possible_filenames(ImageClass class, const char *image_name)
|
|||||||
return TAKE_PTR(l);
|
return TAKE_PTR(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
int image_find(ImageClass class,
|
int image_find(RuntimeScope scope,
|
||||||
|
ImageClass class,
|
||||||
const char *name,
|
const char *name,
|
||||||
const char *root,
|
const char *root,
|
||||||
Image **ret) {
|
Image **ret) {
|
||||||
@ -602,6 +688,7 @@ int image_find(ImageClass class,
|
|||||||
* some root directory.) */
|
* some root directory.) */
|
||||||
int open_flags = root ? O_NOFOLLOW : 0, r;
|
int open_flags = root ? O_NOFOLLOW : 0, r;
|
||||||
|
|
||||||
|
assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL);
|
||||||
assert(class >= 0);
|
assert(class >= 0);
|
||||||
assert(class < _IMAGE_CLASS_MAX);
|
assert(class < _IMAGE_CLASS_MAX);
|
||||||
assert(name);
|
assert(name);
|
||||||
@ -614,11 +701,16 @@ int image_find(ImageClass class,
|
|||||||
if (!names)
|
if (!names)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
NULSTR_FOREACH(path, pick_image_search_path(class)) {
|
_cleanup_strv_free_ char **search = NULL;
|
||||||
|
r = pick_image_search_path(scope, class, &search);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
STRV_FOREACH(path, search) {
|
||||||
_cleanup_free_ char *resolved = NULL;
|
_cleanup_free_ char *resolved = NULL;
|
||||||
_cleanup_closedir_ DIR *d = NULL;
|
_cleanup_closedir_ DIR *d = NULL;
|
||||||
|
|
||||||
r = chase_and_opendir(path, root, CHASE_PREFIX_ROOT, &resolved, &d);
|
r = chase_and_opendir(*path, root, CHASE_PREFIX_ROOT, &resolved, &d);
|
||||||
if (r == -ENOENT)
|
if (r == -ENOENT)
|
||||||
continue;
|
continue;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -722,7 +814,7 @@ int image_find(ImageClass class,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (class == IMAGE_MACHINE && streq(name, ".host")) {
|
if (scope == RUNTIME_SCOPE_SYSTEM && class == IMAGE_MACHINE && streq(name, ".host")) {
|
||||||
r = image_make(class,
|
r = image_make(class,
|
||||||
".host",
|
".host",
|
||||||
/* dir_fd= */ AT_FDCWD,
|
/* dir_fd= */ AT_FDCWD,
|
||||||
@ -771,14 +863,21 @@ int image_from_path(const char *path, Image **ret) {
|
|||||||
ret);
|
ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int image_find_harder(ImageClass class, const char *name_or_path, const char *root, Image **ret) {
|
int image_find_harder(
|
||||||
|
RuntimeScope scope,
|
||||||
|
ImageClass class,
|
||||||
|
const char *name_or_path,
|
||||||
|
const char *root,
|
||||||
|
Image **ret) {
|
||||||
|
|
||||||
if (image_name_is_valid(name_or_path))
|
if (image_name_is_valid(name_or_path))
|
||||||
return image_find(class, name_or_path, root, ret);
|
return image_find(scope, class, name_or_path, root, ret);
|
||||||
|
|
||||||
return image_from_path(name_or_path, ret);
|
return image_from_path(name_or_path, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int image_discover(
|
int image_discover(
|
||||||
|
RuntimeScope scope,
|
||||||
ImageClass class,
|
ImageClass class,
|
||||||
const char *root,
|
const char *root,
|
||||||
Hashmap *h) {
|
Hashmap *h) {
|
||||||
@ -788,15 +887,21 @@ int image_discover(
|
|||||||
* some root directory.) */
|
* some root directory.) */
|
||||||
int open_flags = root ? O_NOFOLLOW : 0, r;
|
int open_flags = root ? O_NOFOLLOW : 0, r;
|
||||||
|
|
||||||
|
assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL);
|
||||||
assert(class >= 0);
|
assert(class >= 0);
|
||||||
assert(class < _IMAGE_CLASS_MAX);
|
assert(class < _IMAGE_CLASS_MAX);
|
||||||
assert(h);
|
assert(h);
|
||||||
|
|
||||||
NULSTR_FOREACH(path, pick_image_search_path(class)) {
|
_cleanup_strv_free_ char **search = NULL;
|
||||||
|
r = pick_image_search_path(scope, class, &search);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
STRV_FOREACH(path, search) {
|
||||||
_cleanup_free_ char *resolved = NULL;
|
_cleanup_free_ char *resolved = NULL;
|
||||||
_cleanup_closedir_ DIR *d = NULL;
|
_cleanup_closedir_ DIR *d = NULL;
|
||||||
|
|
||||||
r = chase_and_opendir(path, root, CHASE_PREFIX_ROOT, &resolved, &d);
|
r = chase_and_opendir(*path, root, CHASE_PREFIX_ROOT, &resolved, &d);
|
||||||
if (r == -ENOENT)
|
if (r == -ENOENT)
|
||||||
continue;
|
continue;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -946,7 +1051,7 @@ int image_discover(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (class == IMAGE_MACHINE && !hashmap_contains(h, ".host")) {
|
if (scope == RUNTIME_SCOPE_SYSTEM && class == IMAGE_MACHINE && !hashmap_contains(h, ".host")) {
|
||||||
_cleanup_(image_unrefp) Image *image = NULL;
|
_cleanup_(image_unrefp) Image *image = NULL;
|
||||||
|
|
||||||
r = image_make(IMAGE_MACHINE,
|
r = image_make(IMAGE_MACHINE,
|
||||||
@ -1063,7 +1168,7 @@ static int rename_auxiliary_file(const char *path, const char *new_name, const c
|
|||||||
return rename_noreplace(AT_FDCWD, path, AT_FDCWD, rs);
|
return rename_noreplace(AT_FDCWD, path, AT_FDCWD, rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int image_rename(Image *i, const char *new_name) {
|
int image_rename(Image *i, const char *new_name, RuntimeScope scope) {
|
||||||
_cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT, name_lock = LOCK_FILE_INIT;
|
_cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT, name_lock = LOCK_FILE_INIT;
|
||||||
_cleanup_free_ char *new_path = NULL, *nn = NULL, *roothash = NULL;
|
_cleanup_free_ char *new_path = NULL, *nn = NULL, *roothash = NULL;
|
||||||
_cleanup_strv_free_ char **settings = NULL;
|
_cleanup_strv_free_ char **settings = NULL;
|
||||||
@ -1098,7 +1203,7 @@ int image_rename(Image *i, const char *new_name) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = image_find(IMAGE_MACHINE, new_name, NULL, NULL);
|
r = image_find(scope, IMAGE_MACHINE, new_name, NULL, NULL);
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
if (r != -ENOENT)
|
if (r != -ENOENT)
|
||||||
@ -1185,7 +1290,7 @@ static int clone_auxiliary_file(const char *path, const char *new_name, const ch
|
|||||||
return copy_file_atomic(path, rs, 0664, COPY_REFLINK);
|
return copy_file_atomic(path, rs, 0664, COPY_REFLINK);
|
||||||
}
|
}
|
||||||
|
|
||||||
int image_clone(Image *i, const char *new_name, bool read_only) {
|
int image_clone(Image *i, const char *new_name, bool read_only, RuntimeScope scope) {
|
||||||
_cleanup_(release_lock_file) LockFile name_lock = LOCK_FILE_INIT;
|
_cleanup_(release_lock_file) LockFile name_lock = LOCK_FILE_INIT;
|
||||||
_cleanup_strv_free_ char **settings = NULL;
|
_cleanup_strv_free_ char **settings = NULL;
|
||||||
_cleanup_free_ char *roothash = NULL;
|
_cleanup_free_ char *roothash = NULL;
|
||||||
@ -1212,7 +1317,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = image_find(IMAGE_MACHINE, new_name, NULL, NULL);
|
r = image_find(scope, IMAGE_MACHINE, new_name, NULL, NULL);
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
if (r != -ENOENT)
|
if (r != -ENOENT)
|
||||||
@ -1646,24 +1751,35 @@ int image_name_lock(const char *name, int operation, LockFile *ret) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool image_in_search_path(
|
bool image_in_search_path(
|
||||||
|
RuntimeScope scope,
|
||||||
ImageClass class,
|
ImageClass class,
|
||||||
const char *root,
|
const char *root,
|
||||||
const char *image) {
|
const char *image) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL);
|
||||||
|
assert(class >= 0);
|
||||||
|
assert(class < _IMAGE_CLASS_MAX);
|
||||||
assert(image);
|
assert(image);
|
||||||
|
|
||||||
NULSTR_FOREACH(path, pick_image_search_path(class)) {
|
_cleanup_strv_free_ char **search = NULL;
|
||||||
|
r = pick_image_search_path(scope, class, &search);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
STRV_FOREACH(path, search) {
|
||||||
const char *p, *q;
|
const char *p, *q;
|
||||||
size_t k;
|
size_t k;
|
||||||
|
|
||||||
if (!empty_or_root(root)) {
|
if (!empty_or_root(root)) {
|
||||||
q = path_startswith(path, root);
|
q = path_startswith(*path, root);
|
||||||
if (!q)
|
if (!q)
|
||||||
continue;
|
continue;
|
||||||
} else
|
} else
|
||||||
q = path;
|
q = *path;
|
||||||
|
|
||||||
p = path_startswith(q, path);
|
p = path_startswith(q, *path);
|
||||||
if (!p)
|
if (!p)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "os-util.h"
|
#include "os-util.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
|
#include "runtime-scope.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
@ -60,14 +61,14 @@ Image *image_ref(Image *i);
|
|||||||
|
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Image*, image_unref);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(Image*, image_unref);
|
||||||
|
|
||||||
int image_find(ImageClass class, const char *name, const char *root, Image **ret);
|
int image_find(RuntimeScope scope, ImageClass class, const char *name, const char *root, Image **ret);
|
||||||
int image_from_path(const char *path, Image **ret);
|
int image_from_path(const char *path, Image **ret);
|
||||||
int image_find_harder(ImageClass class, const char *name_or_path, const char *root, Image **ret);
|
int image_find_harder(RuntimeScope scope, ImageClass class, const char *name_or_path, const char *root, Image **ret);
|
||||||
int image_discover(ImageClass class, const char *root, Hashmap *map);
|
int image_discover(RuntimeScope scope, ImageClass class, const char *root, Hashmap *map);
|
||||||
|
|
||||||
int image_remove(Image *i);
|
int image_remove(Image *i);
|
||||||
int image_rename(Image *i, const char *new_name);
|
int image_rename(Image *i, const char *new_name, RuntimeScope scope);
|
||||||
int image_clone(Image *i, const char *new_name, bool read_only);
|
int image_clone(Image *i, const char *new_name, bool read_only, RuntimeScope scope);
|
||||||
int image_read_only(Image *i, bool b);
|
int image_read_only(Image *i, bool b);
|
||||||
|
|
||||||
const char* image_type_to_string(ImageType t) _const_;
|
const char* image_type_to_string(ImageType t) _const_;
|
||||||
@ -80,7 +81,7 @@ int image_set_limit(Image *i, uint64_t referenced_max);
|
|||||||
|
|
||||||
int image_read_metadata(Image *i, const ImagePolicy *image_policy);
|
int image_read_metadata(Image *i, const ImagePolicy *image_policy);
|
||||||
|
|
||||||
bool image_in_search_path(ImageClass class, const char *root, const char *image);
|
bool image_in_search_path(RuntimeScope scope, ImageClass class, const char *root, const char *image);
|
||||||
|
|
||||||
static inline char **image_extension_release(Image *image, ImageClass class) {
|
static inline char **image_extension_release(Image *image, ImageClass class) {
|
||||||
assert(image);
|
assert(image);
|
||||||
|
@ -2031,7 +2031,7 @@ static int image_discover_and_read_metadata(
|
|||||||
if (!images)
|
if (!images)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
r = image_discover(image_class, arg_root, images);
|
r = image_discover(RUNTIME_SCOPE_SYSTEM, image_class, arg_root, images);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to discover images: %m");
|
return log_error_errno(r, "Failed to discover images: %m");
|
||||||
|
|
||||||
@ -2278,7 +2278,7 @@ static int verb_list(int argc, char **argv, void *userdata) {
|
|||||||
if (!images)
|
if (!images)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
r = image_discover(arg_image_class, arg_root, images);
|
r = image_discover(RUNTIME_SCOPE_SYSTEM, arg_image_class, arg_root, images);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to discover images: %m");
|
return log_error_errno(r, "Failed to discover images: %m");
|
||||||
|
|
||||||
@ -2339,7 +2339,7 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
|||||||
if (!images)
|
if (!images)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = image_discover(image_class, arg_root, images);
|
r = image_discover(RUNTIME_SCOPE_SYSTEM, image_class, arg_root, images);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -46,6 +46,8 @@ typedef struct Manager {
|
|||||||
Hashmap *polkit_registry;
|
Hashmap *polkit_registry;
|
||||||
|
|
||||||
sd_event_source *notify_event;
|
sd_event_source *notify_event;
|
||||||
|
|
||||||
|
RuntimeScope runtime_scope; /* For now only RUNTIME_SCOPE_SYSTEM */
|
||||||
} Manager;
|
} Manager;
|
||||||
|
|
||||||
/* Forward declare so that jobs can call it on exit */
|
/* Forward declare so that jobs can call it on exit */
|
||||||
@ -1730,10 +1732,14 @@ static int manager_new(Manager **ret) {
|
|||||||
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
m = new0(Manager, 1);
|
m = new(Manager, 1);
|
||||||
if (!m)
|
if (!m)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*m = (Manager) {
|
||||||
|
.runtime_scope = RUNTIME_SCOPE_SYSTEM,
|
||||||
|
};
|
||||||
|
|
||||||
r = sd_event_default(&m->event);
|
r = sd_event_default(&m->event);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -1795,7 +1801,7 @@ static int manager_enumerate_image_class(Manager *m, TargetClass class) {
|
|||||||
if (!images)
|
if (!images)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = image_discover((ImageClass) class, NULL, images);
|
r = image_discover(m->runtime_scope, (ImageClass) class, NULL, images);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -2236,7 +2236,8 @@ static int determine_names(void) {
|
|||||||
if (arg_machine) {
|
if (arg_machine) {
|
||||||
_cleanup_(image_unrefp) Image *i = NULL;
|
_cleanup_(image_unrefp) Image *i = NULL;
|
||||||
|
|
||||||
r = image_find(IMAGE_MACHINE, arg_machine, NULL, &i);
|
r = image_find(arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
|
||||||
|
IMAGE_MACHINE, arg_machine, NULL, &i);
|
||||||
if (r == -ENOENT)
|
if (r == -ENOENT)
|
||||||
return log_error_errno(r, "No image for machine '%s'.", arg_machine);
|
return log_error_errno(r, "No image for machine '%s'.", arg_machine);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -1129,7 +1129,7 @@ testcase_unpriv() {
|
|||||||
|
|
||||||
local tmpdir name
|
local tmpdir name
|
||||||
tmpdir="$(mktemp -d /var/tmp/TEST-13-NSPAWN.unpriv.XXX)"
|
tmpdir="$(mktemp -d /var/tmp/TEST-13-NSPAWN.unpriv.XXX)"
|
||||||
name="unpriv-${tmpdir##*.}"
|
name="unprv-${tmpdir##*.}"
|
||||||
trap 'rm -fr ${tmpdir@Q} || true; rm -f /run/verity.d/test-13-nspawn-${name@Q} || true' RETURN ERR
|
trap 'rm -fr ${tmpdir@Q} || true; rm -f /run/verity.d/test-13-nspawn-${name@Q} || true' RETURN ERR
|
||||||
create_dummy_ddi "$tmpdir" "$name"
|
create_dummy_ddi "$tmpdir" "$name"
|
||||||
chown --recursive testuser: "$tmpdir"
|
chown --recursive testuser: "$tmpdir"
|
||||||
@ -1141,6 +1141,17 @@ testcase_unpriv() {
|
|||||||
-- \
|
-- \
|
||||||
systemd-nspawn --pipe --private-network --register=no --keep-unit --image="$tmpdir/$name.raw" echo hello >"$tmpdir/stdout.txt"
|
systemd-nspawn --pipe --private-network --register=no --keep-unit --image="$tmpdir/$name.raw" echo hello >"$tmpdir/stdout.txt"
|
||||||
echo hello | cmp "$tmpdir/stdout.txt" -
|
echo hello | cmp "$tmpdir/stdout.txt" -
|
||||||
|
|
||||||
|
# Make sure per-user search path logic works
|
||||||
|
systemd-run --pipe --uid=testuser mkdir -p /home/testuser/.local/state/machines
|
||||||
|
systemd-run --pipe --uid=testuser ln -s "$tmpdir/$name.raw" /home/testuser/.local/state/machines/"x$name.raw"
|
||||||
|
systemd-run \
|
||||||
|
--pipe \
|
||||||
|
--uid=testuser \
|
||||||
|
--property=Delegate=yes \
|
||||||
|
-- \
|
||||||
|
systemd-nspawn --pipe --private-network --register=no --keep-unit --machine="x$name" echo hello >"$tmpdir/stdout.txt"
|
||||||
|
echo hello | cmp "$tmpdir/stdout.txt" -
|
||||||
}
|
}
|
||||||
|
|
||||||
testcase_fuse() {
|
testcase_fuse() {
|
||||||
|
@ -615,6 +615,10 @@ grep -q -F '{"name":"b","type":"raw","class":"portable","ro":false,"path":"/run/
|
|||||||
grep -q -F '{"name":"c","type":"raw","class":"sysext","ro":false,"path":"/run/extensions/c.raw"' /tmp/discover.json
|
grep -q -F '{"name":"c","type":"raw","class":"sysext","ro":false,"path":"/run/extensions/c.raw"' /tmp/discover.json
|
||||||
rm /tmp/discover.json /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw
|
rm /tmp/discover.json /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw
|
||||||
|
|
||||||
|
systemd-dissect --discover --system
|
||||||
|
systemd-dissect --discover --user
|
||||||
|
systemd-dissect --discover --system --user
|
||||||
|
|
||||||
LOOP="$(systemd-dissect --attach --loop-ref=waldo "$MINIMAL_IMAGE.raw")"
|
LOOP="$(systemd-dissect --attach --loop-ref=waldo "$MINIMAL_IMAGE.raw")"
|
||||||
|
|
||||||
# Wait until the symlinks we want to test are established
|
# Wait until the symlinks we want to test are established
|
||||||
|
Loading…
Reference in New Issue
Block a user