summaryrefslogtreecommitdiffstats
path: root/src/portable
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:40 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:40 +0000
commitfc53809803cd2bc2434e312b19a18fa36776da12 (patch)
treeb4b43bd6538f51965ce32856e9c053d0f90919c8 /src/portable
parentAdding upstream version 255.5. (diff)
downloadsystemd-upstream.tar.xz
systemd-upstream.zip
Adding upstream version 256.upstream/256upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/portable')
-rw-r--r--src/portable/portable.c213
-rw-r--r--src/portable/portable.h3
-rw-r--r--src/portable/portablectl.c77
-rw-r--r--src/portable/portabled-bus.c10
-rw-r--r--src/portable/portabled-image-bus.c19
-rw-r--r--src/portable/portabled.c29
-rw-r--r--src/portable/profile/default/service.conf2
-rw-r--r--src/portable/profile/trusted/service.conf2
8 files changed, 241 insertions, 114 deletions
diff --git a/src/portable/portable.c b/src/portable/portable.c
index 3b2a379..53418c4 100644
--- a/src/portable/portable.c
+++ b/src/portable/portable.c
@@ -33,6 +33,7 @@
#include "path-lookup.h"
#include "portable.h"
#include "process-util.h"
+#include "rm-rf.h"
#include "selinux-util.h"
#include "set.h"
#include "signal-util.h"
@@ -42,6 +43,7 @@
#include "strv.h"
#include "tmpfile-util.h"
#include "user-util.h"
+#include "vpick.h"
/* Markers used in the first line of our 20-portable.conf unit file drop-in to determine, that a) the unit file was
* dropped there by the portable service logic and b) for which image it was dropped there. */
@@ -181,7 +183,7 @@ static int extract_now(
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
_cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
+ _cleanup_(lookup_paths_done) LookupPaths paths = {};
_cleanup_close_ int os_release_fd = -EBADF;
_cleanup_free_ char *os_release_path = NULL;
const char *os_release_id;
@@ -361,7 +363,13 @@ static int portable_extract_by_path(
assert(path);
- r = loop_device_make_by_path(path, O_RDONLY, /* sector_size= */ UINT32_MAX, LO_FLAGS_PARTSCAN, LOCK_SH, &d);
+ r = loop_device_make_by_path(
+ path,
+ O_RDONLY,
+ /* sector_size= */ UINT32_MAX,
+ LO_FLAGS_PARTSCAN,
+ LOCK_SH,
+ &d);
if (r == -EISDIR) {
_cleanup_free_ char *image_name = NULL;
@@ -383,6 +391,21 @@ static int portable_extract_by_path(
_cleanup_(rmdir_and_freep) char *tmpdir = NULL;
_cleanup_close_pair_ int seq[2] = EBADF_PAIR;
_cleanup_(sigkill_waitp) pid_t child = 0;
+ DissectImageFlags flags =
+ DISSECT_IMAGE_READ_ONLY |
+ DISSECT_IMAGE_GENERIC_ROOT |
+ DISSECT_IMAGE_REQUIRE_ROOT |
+ DISSECT_IMAGE_DISCARD_ON_LOOP |
+ DISSECT_IMAGE_RELAX_VAR_CHECK |
+ DISSECT_IMAGE_USR_NO_ROOT |
+ DISSECT_IMAGE_ADD_PARTITION_DEVICES |
+ DISSECT_IMAGE_PIN_PARTITION_DEVICES |
+ DISSECT_IMAGE_ALLOW_USERSPACE_VERITY;
+
+ if (path_is_extension)
+ flags |= DISSECT_IMAGE_VALIDATE_OS_EXT | (relax_extension_release_check ? DISSECT_IMAGE_RELAX_EXTENSION_CHECK : 0);
+ else
+ flags |= DISSECT_IMAGE_VALIDATE_OS;
/* We now have a loopback block device, let's fork off a child in its own mount namespace, mount it
* there, and extract the metadata we need. The metadata is sent from the child back to us. */
@@ -398,14 +421,7 @@ static int portable_extract_by_path(
/* verity= */ NULL,
/* mount_options= */ NULL,
image_policy,
- DISSECT_IMAGE_READ_ONLY |
- DISSECT_IMAGE_GENERIC_ROOT |
- DISSECT_IMAGE_REQUIRE_ROOT |
- DISSECT_IMAGE_DISCARD_ON_LOOP |
- DISSECT_IMAGE_RELAX_VAR_CHECK |
- DISSECT_IMAGE_USR_NO_ROOT |
- DISSECT_IMAGE_ADD_PARTITION_DEVICES |
- DISSECT_IMAGE_PIN_PARTITION_DEVICES,
+ flags,
&m);
if (r == -ENOPKG)
sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Couldn't identify a suitable partition table or file system in '%s'.", path);
@@ -427,15 +443,8 @@ static int portable_extract_by_path(
if (r < 0)
return r;
if (r == 0) {
- DissectImageFlags flags = DISSECT_IMAGE_READ_ONLY;
-
seq[0] = safe_close(seq[0]);
- if (path_is_extension)
- flags |= DISSECT_IMAGE_VALIDATE_OS_EXT | (relax_extension_release_check ? DISSECT_IMAGE_RELAX_EXTENSION_CHECK : 0);
- else
- flags |= DISSECT_IMAGE_VALIDATE_OS;
-
r = dissected_image_mount(
m,
tmpdir,
@@ -556,6 +565,7 @@ static int extract_image_and_extensions(
_cleanup_free_ char *id = NULL, *version_id = NULL, *sysext_level = NULL, *confext_level = NULL;
_cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
_cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL, *extension_releases = NULL;
+ _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
_cleanup_strv_free_ char **valid_prefixes = NULL;
_cleanup_(image_unrefp) Image *image = NULL;
@@ -564,7 +574,27 @@ static int extract_image_and_extensions(
assert(name_or_path);
- r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image);
+ /* If we get a path, then check if it can be resolved with vpick. We need this as we might just
+ * get a simple image name, which would make vpick error out. */
+ if (path_is_absolute(name_or_path)) {
+ r = path_pick(/* toplevel_path= */ NULL,
+ /* toplevel_fd= */ AT_FDCWD,
+ name_or_path,
+ &pick_filter_image_any,
+ PICK_ARCHITECTURE|PICK_TRIES|PICK_RESOLVE,
+ &result);
+ if (r < 0)
+ return r;
+ if (!result.path)
+ return log_debug_errno(
+ SYNTHETIC_ERRNO(ENOENT),
+ "No matching entry in .v/ directory %s found.",
+ name_or_path);
+
+ name_or_path = result.path;
+ }
+
+ r = image_find_harder(IMAGE_PORTABLE, name_or_path, /* root= */ NULL, &image);
if (r < 0)
return r;
@@ -580,9 +610,29 @@ static int extract_image_and_extensions(
}
STRV_FOREACH(p, extension_image_paths) {
+ _cleanup_(pick_result_done) PickResult ext_result = PICK_RESULT_NULL;
_cleanup_(image_unrefp) Image *new = NULL;
+ const char *path = *p;
+
+ if (path_is_absolute(*p)) {
+ r = path_pick(/* toplevel_path= */ NULL,
+ /* toplevel_fd= */ AT_FDCWD,
+ *p,
+ &pick_filter_image_any,
+ PICK_ARCHITECTURE|PICK_TRIES|PICK_RESOLVE,
+ &ext_result);
+ if (r < 0)
+ return r;
+ if (!ext_result.path)
+ return log_debug_errno(
+ SYNTHETIC_ERRNO(ENOENT),
+ "No matching entry in .v/ directory %s found.",
+ *p);
- r = image_find_harder(IMAGE_PORTABLE, *p, NULL, &new);
+ path = ext_result.path;
+ }
+
+ r = image_find_harder(IMAGE_PORTABLE, path, NULL, &new);
if (r < 0)
return r;
@@ -1341,7 +1391,7 @@ static int attach_unit_file(
return 0;
}
-static int image_symlink(
+static int image_target_path(
const char *image_path,
PortableFlags flags,
char **ret) {
@@ -1367,37 +1417,66 @@ static int image_symlink(
return 0;
}
-static int install_image_symlink(
+static int install_image(
const char *image_path,
PortableFlags flags,
PortableChange **changes,
size_t *n_changes) {
- _cleanup_free_ char *sl = NULL;
+ _cleanup_free_ char *target = NULL;
int r;
assert(image_path);
- /* 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 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
+ * copied instead. */
if (image_in_search_path(IMAGE_PORTABLE, NULL, image_path))
return 0;
- r = image_symlink(image_path, flags, &sl);
+ r = image_target_path(image_path, flags, &target);
if (r < 0)
return log_debug_errno(r, "Failed to generate image symlink path: %m");
- (void) mkdir_parents(sl, 0755);
+ (void) mkdir_parents(target, 0755);
+
+ if (flags & PORTABLE_MIXED_COPY_LINK) {
+ r = copy_tree(image_path,
+ target,
+ UID_INVALID,
+ GID_INVALID,
+ COPY_REFLINK | COPY_FSYNC | COPY_FSYNC_FULL | COPY_SYNCFS,
+ /* denylist= */ NULL,
+ /* subvolumes= */ NULL);
+ if (r < 0)
+ return log_debug_errno(
+ r,
+ "Failed to copy %s %s %s: %m",
+ image_path,
+ special_glyph(SPECIAL_GLYPH_ARROW_RIGHT),
+ target);
- if (symlink(image_path, sl) < 0)
- return log_debug_errno(errno, "Failed to link %s %s %s: %m", image_path, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), sl);
+ } else {
+ if (symlink(image_path, target) < 0)
+ return log_debug_errno(
+ errno,
+ "Failed to link %s %s %s: %m",
+ image_path,
+ special_glyph(SPECIAL_GLYPH_ARROW_RIGHT),
+ target);
+ }
- (void) portable_changes_add(changes, n_changes, PORTABLE_SYMLINK, sl, image_path);
+ (void) portable_changes_add(
+ changes,
+ n_changes,
+ (flags & PORTABLE_MIXED_COPY_LINK) ? PORTABLE_COPY : PORTABLE_SYMLINK,
+ target,
+ image_path);
return 0;
}
-static int install_image_and_extensions_symlinks(
+static int install_image_and_extensions(
const Image *image,
OrderedHashmap *extension_images,
PortableFlags flags,
@@ -1410,12 +1489,12 @@ static int install_image_and_extensions_symlinks(
assert(image);
ORDERED_HASHMAP_FOREACH(ext, extension_images) {
- r = install_image_symlink(ext->path, flags, changes, n_changes);
+ r = install_image(ext->path, flags, changes, n_changes);
if (r < 0)
return r;
}
- r = install_image_symlink(image->path, flags, changes, n_changes);
+ r = install_image(image->path, flags, changes, n_changes);
if (r < 0)
return r;
@@ -1436,6 +1515,7 @@ static void log_portable_verb(
const char *verb,
const char *message_id,
const char *image_path,
+ const char *profile,
OrderedHashmap *extension_images,
char **extension_image_paths,
PortableFlags flags) {
@@ -1494,12 +1574,14 @@ static void log_portable_verb(
LOG_CONTEXT_PUSH_STRV(extension_base_names);
log_struct(LOG_INFO,
- LOG_MESSAGE("Successfully %s%s '%s%s%s'",
+ LOG_MESSAGE("Successfully %s%s '%s%s%s%s%s'",
verb,
FLAGS_SET(flags, PORTABLE_RUNTIME) ? " ephemeral" : "",
image_path,
isempty(extensions_joined) ? "" : "' and its extension(s) '",
- strempty(extensions_joined)),
+ strempty(extensions_joined),
+ isempty(profile) ? "" : "' using profile '",
+ strempty(profile)),
message_id,
"PORTABLE_ROOT=%s", strna(root_base_name));
}
@@ -1519,7 +1601,7 @@ int portable_attach(
_cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL, *extension_releases = NULL;
_cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
+ _cleanup_(lookup_paths_done) LookupPaths paths = {};
_cleanup_strv_free_ char **valid_prefixes = NULL;
_cleanup_(image_unrefp) Image *image = NULL;
PortableMetadata *item;
@@ -1608,14 +1690,15 @@ int portable_attach(
return sd_bus_error_set_errnof(error, r, "Failed to attach unit '%s': %m", item->name);
}
- /* We don't care too much for the image symlink, it's just a convenience thing, it's not necessary for proper
- * operation otherwise. */
- (void) install_image_and_extensions_symlinks(image, extension_images, flags, changes, n_changes);
+ /* 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. */
+ (void) install_image_and_extensions(image, extension_images, flags, changes, n_changes);
log_portable_verb(
"attached",
"MESSAGE_ID=" SD_MESSAGE_PORTABLE_ATTACHED_STR,
image->path,
+ profile,
extension_images,
/* extension_image_paths= */ NULL,
flags);
@@ -1650,6 +1733,7 @@ static bool marker_matches_images(const char *marker, const char *name_or_path,
while (!isempty(marker))
STRV_FOREACH(image_name_or_path, root_and_extensions) {
_cleanup_free_ char *image = NULL, *base_image = NULL, *base_image_name_or_path = NULL;
+ _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
r = extract_first_word(&marker, &image, ":", EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
if (r < 0)
@@ -1661,9 +1745,23 @@ static bool marker_matches_images(const char *marker, const char *name_or_path,
if (r < 0)
return log_debug_errno(r, "Failed to extract image name from %s, ignoring: %m", image);
- r = path_extract_image_name(*image_name_or_path, &base_image_name_or_path);
+ r = path_pick(/* toplevel_path= */ NULL,
+ /* toplevel_fd= */ AT_FDCWD,
+ *image_name_or_path,
+ &pick_filter_image_any,
+ PICK_ARCHITECTURE|PICK_TRIES|PICK_RESOLVE,
+ &result);
+ if (r < 0)
+ return r;
+ if (!result.path)
+ return log_debug_errno(
+ SYNTHETIC_ERRNO(ENOENT),
+ "No matching entry in .v/ directory %s found.",
+ *image_name_or_path);
+
+ r = path_extract_image_name(result.path, &base_image_name_or_path);
if (r < 0)
- return log_debug_errno(r, "Failed to extract image name from %s, ignoring: %m", *image_name_or_path);
+ return log_debug_errno(r, "Failed to extract image name from %s, ignoring: %m", result.path);
if (!streq(base_image, base_image_name_or_path)) {
if (match_all)
@@ -1746,7 +1844,7 @@ int portable_detach(
size_t *n_changes,
sd_bus_error *error) {
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
+ _cleanup_(lookup_paths_done) LookupPaths paths = {};
_cleanup_set_free_ Set *unit_files = NULL, *markers = NULL;
_cleanup_free_ char *extensions = NULL;
_cleanup_closedir_ DIR *d = NULL;
@@ -1875,34 +1973,24 @@ int portable_detach(
portable_changes_add_with_prefix(changes, n_changes, PORTABLE_UNLINK, where, md, NULL);
}
- /* Now, also drop any image symlink, for images outside of the sarch path */
+ /* Now, also drop any image symlink or copy, for images outside of the sarch path */
SET_FOREACH(item, markers) {
- _cleanup_free_ char *sl = NULL;
- struct stat st;
+ _cleanup_free_ char *target = NULL;
- r = image_symlink(item, flags, &sl);
+ r = image_target_path(item, flags, &target);
if (r < 0) {
- log_debug_errno(r, "Failed to determine image symlink for '%s', ignoring: %m", item);
+ log_debug_errno(r, "Failed to determine image path for '%s', ignoring: %m", item);
continue;
}
- if (lstat(sl, &st) < 0) {
- log_debug_errno(errno, "Failed to stat '%s', ignoring: %m", sl);
- continue;
- }
-
- if (!S_ISLNK(st.st_mode)) {
- log_debug("Image '%s' is not a symlink, ignoring.", sl);
- continue;
- }
-
- if (unlink(sl) < 0) {
- log_debug_errno(errno, "Can't remove image symlink '%s': %m", sl);
+ r = rm_rf(target, REMOVE_ROOT | REMOVE_PHYSICAL | REMOVE_MISSING_OK | REMOVE_SYNCFS);
+ if (r < 0) {
+ log_debug_errno(r, "Can't remove image '%s': %m", target);
- if (errno != ENOENT && ret >= 0)
- ret = -errno;
+ if (r != -ENOENT)
+ RET_GATHER(ret, r);
} else
- portable_changes_add(changes, n_changes, PORTABLE_UNLINK, sl, NULL);
+ portable_changes_add(changes, n_changes, PORTABLE_UNLINK, target, NULL);
}
/* Try to remove the unit file directory, if we can */
@@ -1913,6 +2001,7 @@ int portable_detach(
"detached",
"MESSAGE_ID=" SD_MESSAGE_PORTABLE_DETACHED_STR,
name_or_path,
+ /* profile= */ NULL,
/* extension_images= */ NULL,
extension_image_paths,
flags);
@@ -1941,7 +2030,7 @@ static int portable_get_state_internal(
PortableState *ret,
sd_bus_error *error) {
- _cleanup_(lookup_paths_free) LookupPaths paths = {};
+ _cleanup_(lookup_paths_done) LookupPaths paths = {};
bool found_enabled = false, found_running = false;
_cleanup_set_free_ Set *unit_files = NULL;
_cleanup_closedir_ DIR *d = NULL;
diff --git a/src/portable/portable.h b/src/portable/portable.h
index c4a9d51..f5bb190 100644
--- a/src/portable/portable.h
+++ b/src/portable/portable.h
@@ -27,7 +27,8 @@ typedef enum PortableFlags {
PORTABLE_FORCE_EXTENSION = 1 << 2, /* Public API via DBUS, do not change */
PORTABLE_PREFER_COPY = 1 << 3,
PORTABLE_PREFER_SYMLINK = 1 << 4,
- PORTABLE_REATTACH = 1 << 5,
+ PORTABLE_MIXED_COPY_LINK = 1 << 5,
+ PORTABLE_REATTACH = 1 << 6,
_PORTABLE_MASK_PUBLIC = PORTABLE_RUNTIME | PORTABLE_FORCE_ATTACH | PORTABLE_FORCE_EXTENSION,
_PORTABLE_TYPE_MAX,
_PORTABLE_TYPE_INVALID = -EINVAL,
diff --git a/src/portable/portablectl.c b/src/portable/portablectl.c
index 1588b17..57b930d 100644
--- a/src/portable/portablectl.c
+++ b/src/portable/portablectl.c
@@ -50,6 +50,7 @@ static bool arg_now = false;
static bool arg_no_block = false;
static char **arg_extension_images = NULL;
static bool arg_force = false;
+static bool arg_clean = false;
STATIC_DESTRUCTOR_REGISTER(arg_extension_images, strv_freep);
@@ -769,13 +770,49 @@ static int maybe_stop_enable_restart(sd_bus *bus, sd_bus_message *reply) {
return 0;
}
-static int maybe_stop_disable(sd_bus *bus, char *image, char *argv[]) {
+static int maybe_clean_units(sd_bus *bus, char **units) {
+ int r;
+
+ assert(bus);
+
+ if (!arg_clean)
+ return 0;
+
+ STRV_FOREACH(name, units) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "CleanUnit");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "s", *name);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_strv(m, STRV_MAKE("all", "fdstore"));
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_call(bus, m, 0, &error, NULL);
+ if (r < 0)
+ return log_error_errno(
+ r,
+ "Failed to call CleanUnit on portable service %s: %s",
+ *name,
+ bus_error_message(&error, r));
+ }
+
+ return 0;
+}
+
+static int maybe_stop_disable_clean(sd_bus *bus, char *image, char *argv[]) {
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *wait = NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- _cleanup_strv_free_ char **matches = NULL;
+ _cleanup_strv_free_ char **matches = NULL, **units = NULL;
int r;
- if (!arg_enable && !arg_now)
+ if (!arg_enable && !arg_now && !arg_clean)
return 0;
r = determine_matches(argv[1], argv + 2, true, &matches);
@@ -829,6 +866,10 @@ static int maybe_stop_disable(sd_bus *bus, char *image, char *argv[]) {
(void) maybe_start_stop_restart(bus, name, "StopUnit", wait);
(void) maybe_enable_disable(bus, name, false);
+
+ r = strv_extend(&units, name);
+ if (r < 0)
+ return log_oom();
}
r = sd_bus_message_exit_container(reply);
@@ -840,6 +881,9 @@ static int maybe_stop_disable(sd_bus *bus, char *image, char *argv[]) {
if (r < 0)
return r;
+ /* Need to ensure all units are stopped before calling CleanUnit, as files might be in use. */
+ (void) maybe_clean_units(bus, units);
+
return 0;
}
@@ -942,7 +986,7 @@ static int detach_image(int argc, char *argv[], void *userdata) {
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
- (void) maybe_stop_disable(bus, image, argv);
+ (void) maybe_stop_disable_clean(bus, image, argv);
method = strv_isempty(arg_extension_images) && !arg_force ? "DetachImage" : "DetachImageWithExtensions";
@@ -1030,7 +1074,7 @@ static int list_images(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
- if (table_get_rows(table) > 1) {
+ if (!table_isempty(table)) {
r = table_set_sort(table, (size_t) 0);
if (r < 0)
return table_log_sort_error(r);
@@ -1043,10 +1087,10 @@ static int list_images(int argc, char *argv[], void *userdata) {
}
if (arg_legend) {
- if (table_get_rows(table) > 1)
- printf("\n%zu images listed.\n", table_get_rows(table) - 1);
- else
+ if (table_isempty(table))
printf("No images.\n");
+ else
+ printf("\n%zu images listed.\n", table_get_rows(table) - 1);
}
return 0;
@@ -1251,7 +1295,8 @@ static int help(int argc, char *argv[], void *userdata) {
" -M --machine=CONTAINER Operate on local container\n"
" -q --quiet Suppress informational messages\n"
" -p --profile=PROFILE Pick security profile for portable service\n"
- " --copy=copy|auto|symlink Prefer copying or symlinks if possible\n"
+ " --copy=copy|auto|symlink|mixed\n"
+ " Pick copying or symlinking of resources\n"
" --runtime Attach portable service until next reboot only\n"
" --no-reload Don't reload the system and service manager\n"
" --cat When inspecting include unit and os-release file\n"
@@ -1264,6 +1309,9 @@ static int help(int argc, char *argv[], void *userdata) {
" --extension=PATH Extend the image with an overlay\n"
" --force Skip 'already active' check when attaching or\n"
" detaching an image (with extensions)\n"
+ " --clean When detaching, also remove configuration, state,\n"
+ " cache, logs or runtime data of the portable\n"
+ " service(s)\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
ansi_highlight(),
@@ -1290,6 +1338,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_NO_BLOCK,
ARG_EXTENSION,
ARG_FORCE,
+ ARG_CLEAN,
};
static const struct option options[] = {
@@ -1311,6 +1360,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "no-block", no_argument, NULL, ARG_NO_BLOCK },
{ "extension", required_argument, NULL, ARG_EXTENSION },
{ "force", no_argument, NULL, ARG_FORCE },
+ { "clean", no_argument, NULL, ARG_CLEAN },
{}
};
@@ -1372,12 +1422,13 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_COPY:
if (streq(optarg, "auto"))
arg_copy_mode = NULL;
- else if (STR_IN_SET(optarg, "copy", "symlink"))
+ else if (STR_IN_SET(optarg, "copy", "symlink", "mixed"))
arg_copy_mode = optarg;
else if (streq(optarg, "help")) {
puts("auto\n"
"copy\n"
- "symlink");
+ "symlink\n"
+ "mixed\n");
return 0;
} else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@@ -1419,6 +1470,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_force = true;
break;
+ case ARG_CLEAN:
+ arg_clean = true;
+ break;
+
case '?':
return -EINVAL;
diff --git a/src/portable/portabled-bus.c b/src/portable/portabled-bus.c
index 0d55180..4f239e2 100644
--- a/src/portable/portabled-bus.c
+++ b/src/portable/portabled-bus.c
@@ -320,11 +320,8 @@ static int method_detach_image(sd_bus_message *message, void *userdata, sd_bus_e
r = bus_verify_polkit_async(
message,
- CAP_SYS_ADMIN,
"org.freedesktop.portable1.attach-images",
- NULL,
- false,
- UID_INVALID,
+ /* details= */ NULL,
&m->polkit_registry,
error);
if (r < 0)
@@ -377,11 +374,8 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus
r = bus_verify_polkit_async(
message,
- CAP_SYS_ADMIN,
"org.freedesktop.portable1.manage-images",
- NULL,
- false,
- UID_INVALID,
+ /* details= */ NULL,
&m->polkit_registry,
error);
if (r < 0)
diff --git a/src/portable/portabled-image-bus.c b/src/portable/portabled-image-bus.c
index 1f61c3b..8db5574 100644
--- a/src/portable/portabled-image-bus.c
+++ b/src/portable/portabled-image-bus.c
@@ -366,6 +366,8 @@ int bus_image_common_attach(
flags |= PORTABLE_PREFER_SYMLINK;
else if (streq(copy_mode, "copy"))
flags |= PORTABLE_PREFER_COPY;
+ else if (streq(copy_mode, "mixed"))
+ flags |= PORTABLE_MIXED_COPY_LINK;
else if (!isempty(copy_mode))
return sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_ARGS, "Unknown copy mode '%s'", copy_mode);
@@ -451,11 +453,8 @@ static int bus_image_method_detach(
r = bus_verify_polkit_async(
message,
- CAP_SYS_ADMIN,
"org.freedesktop.portable1.attach-images",
- NULL,
- false,
- UID_INVALID,
+ /* details= */ NULL,
&m->polkit_registry,
error);
if (r < 0)
@@ -698,6 +697,8 @@ int bus_image_common_reattach(
flags |= PORTABLE_PREFER_SYMLINK;
else if (streq(copy_mode, "copy"))
flags |= PORTABLE_PREFER_COPY;
+ else if (streq(copy_mode, "mixed"))
+ flags |= PORTABLE_MIXED_COPY_LINK;
else if (!isempty(copy_mode))
return sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_ARGS, "Unknown copy mode '%s'", copy_mode);
@@ -1010,11 +1011,8 @@ int bus_image_acquire(
if (mode == BUS_IMAGE_AUTHENTICATE_ALL) {
r = bus_verify_polkit_async(
message,
- CAP_SYS_ADMIN,
polkit_action,
- NULL,
- false,
- UID_INVALID,
+ /* details= */ NULL,
&m->polkit_registry,
error);
if (r < 0)
@@ -1064,11 +1062,8 @@ int bus_image_acquire(
if (mode == BUS_IMAGE_AUTHENTICATE_BY_PATH) {
r = bus_verify_polkit_async(
message,
- CAP_SYS_ADMIN,
polkit_action,
- NULL,
- false,
- UID_INVALID,
+ /* details= */ NULL,
&m->polkit_registry,
error);
if (r < 0)
diff --git a/src/portable/portabled.c b/src/portable/portabled.c
index 136c5fa..d46ac01 100644
--- a/src/portable/portabled.c
+++ b/src/portable/portabled.c
@@ -65,7 +65,7 @@ static Manager* manager_unref(Manager *m) {
sd_event_source_unref(m->image_cache_defer_event);
- bus_verify_polkit_async_registry_free(m->polkit_registry);
+ hashmap_free(m->polkit_registry);
sd_bus_flush_close_unref(m->bus);
sd_event_unref(m->event);
@@ -122,17 +122,6 @@ static bool check_idle(void *userdata) {
return !m->operations;
}
-static int manager_run(Manager *m) {
- assert(m);
-
- return bus_event_loop_with_idle(
- m->event,
- m->bus,
- "org.freedesktop.portable1",
- DEFAULT_EXIT_USEC,
- check_idle, m);
-}
-
static int run(int argc, char *argv[]) {
_cleanup_(manager_unrefp) Manager *m = NULL;
int r;
@@ -152,7 +141,7 @@ static int run(int argc, char *argv[]) {
if (argc != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18) >= 0);
r = manager_new(&m);
if (r < 0)
@@ -162,16 +151,20 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to fully start up daemon: %m");
- log_debug("systemd-portabled running as pid " PID_FMT, getpid_cached());
r = sd_notify(false, NOTIFY_READY);
if (r < 0)
log_warning_errno(r, "Failed to send readiness notification, ignoring: %m");
- r = manager_run(m);
+ r = bus_event_loop_with_idle(
+ m->event,
+ m->bus,
+ "org.freedesktop.portable1",
+ DEFAULT_EXIT_USEC,
+ check_idle, m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to run main loop: %m");
- (void) sd_notify(false, NOTIFY_STOPPING);
- log_debug("systemd-portabled stopped as pid " PID_FMT, getpid_cached());
- return r;
+ return 0;
}
DEFINE_MAIN_FUNCTION(run);
diff --git a/src/portable/profile/default/service.conf b/src/portable/profile/default/service.conf
index 230aa60..5c447d6 100644
--- a/src/portable/profile/default/service.conf
+++ b/src/portable/profile/default/service.conf
@@ -4,7 +4,7 @@
MountAPIVFS=yes
BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout
BindReadOnlyPaths=/etc/machine-id
-BindReadOnlyPaths=/etc/resolv.conf
+BindReadOnlyPaths=-/etc/resolv.conf
BindReadOnlyPaths=/run/dbus/system_bus_socket
DynamicUser=yes
RemoveIPC=yes
diff --git a/src/portable/profile/trusted/service.conf b/src/portable/profile/trusted/service.conf
index 04deeb2..144d4f6 100644
--- a/src/portable/profile/trusted/service.conf
+++ b/src/portable/profile/trusted/service.conf
@@ -5,4 +5,4 @@ MountAPIVFS=yes
PrivateTmp=yes
BindPaths=/run
BindReadOnlyPaths=/etc/machine-id
-BindReadOnlyPaths=/etc/resolv.conf
+BindReadOnlyPaths=-/etc/resolv.conf