]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
portable: ensure PORTABLE_FORCE_ATTACH works even when there is a leftover unit
authorLuca Boccassi <bluca@debian.org>
Fri, 30 Aug 2024 16:55:18 +0000 (17:55 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Mon, 2 Sep 2024 14:33:29 +0000 (15:33 +0100)
Force means force, we skip checks with PID1 for existing units, but
then bail out with EEXIST if the files are actually there. Overwrite
everything instead.

src/portable/portable.c
test/units/TEST-29-PORTABLE.sh

index 08e9bc0113915d10de1c8c1bf913c0ae8646499b..af7d9552da45808ef094c3250141da955f094f54 100644 (file)
@@ -1255,8 +1255,12 @@ static int install_profile_dropin(
                 return -ENOMEM;
 
         if (flags & PORTABLE_PREFER_COPY) {
+                CopyFlags copy_flags = COPY_REFLINK|COPY_FSYNC;
 
-                r = copy_file_atomic(from, dropin, 0644, COPY_REFLINK|COPY_FSYNC);
+                if (flags & PORTABLE_FORCE_ATTACH)
+                        copy_flags |= COPY_REPLACE;
+
+                r = copy_file_atomic(from, dropin, 0644, copy_flags);
                 if (r < 0)
                         return log_debug_errno(r, "Failed to copy %s %s %s: %m", from, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), dropin);
 
@@ -1264,8 +1268,12 @@ static int install_profile_dropin(
 
         } else {
 
-                if (symlink(from, dropin) < 0)
-                        return log_debug_errno(errno, "Failed to link %s %s %s: %m", from, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), dropin);
+                if (flags & PORTABLE_FORCE_ATTACH)
+                        r = symlink_atomic(from, dropin);
+                else
+                        r = RET_NERRNO(symlink(from, dropin));
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to link %s %s %s: %m", from, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), dropin);
 
                 (void) portable_changes_add(changes, n_changes, PORTABLE_SYMLINK, dropin, from);
         }
@@ -1351,15 +1359,23 @@ static int attach_unit_file(
 
         if ((flags & PORTABLE_PREFER_SYMLINK) && m->source) {
 
-                if (symlink(m->source, path) < 0)
-                        return log_debug_errno(errno, "Failed to symlink unit file '%s': %m", path);
+                if (flags & PORTABLE_FORCE_ATTACH)
+                        r = symlink_atomic(m->source, path);
+                else
+                        r = RET_NERRNO(symlink(m->source, path));
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to symlink unit file '%s': %m", path);
 
                 (void) portable_changes_add(changes, n_changes, PORTABLE_SYMLINK, path, m->source);
 
         } else {
+                LinkTmpfileFlags link_flags = LINK_TMPFILE_SYNC;
                 _cleanup_(unlink_and_freep) char *tmp = NULL;
                 _cleanup_close_ int fd = -EBADF;
 
+                if (flags & PORTABLE_FORCE_ATTACH)
+                        link_flags |= LINK_TMPFILE_REPLACE;
+
                 (void) mac_selinux_create_file_prepare_label(path, m->selinux_label);
 
                 fd = open_tmpfile_linkable(path, O_WRONLY|O_CLOEXEC, &tmp);
@@ -1374,7 +1390,7 @@ static int attach_unit_file(
                 if (fchmod(fd, 0644) < 0)
                         return log_debug_errno(errno, "Failed to change unit file access mode for '%s': %m", path);
 
-                r = link_tmpfile(fd, tmp, path, LINK_TMPFILE_SYNC);
+                r = link_tmpfile(fd, tmp, path, link_flags);
                 if (r < 0)
                         return log_debug_errno(r, "Failed to install unit file '%s': %m", path);
 
index 41dce4d48a0da90088f3b12cdc2a1d3dbcd0edd0..501d492c7d9198b62874386ace9df2564e486bc6 100755 (executable)
@@ -73,6 +73,21 @@ busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/
 
 # Ensure we don't regress (again) when using --force
 
+mkdir -p /run/systemd/system.attached/minimal-app0.service.d/
+cat <<EOF >/run/systemd/system.attached/minimal-app0.service
+[Unit]
+Description=Minimal App 0
+EOF
+cat <<EOF >/run/systemd/system.attached/minimal-app0.service.d/10-profile.conf
+[Unit]
+Description=Minimal App 0
+EOF
+cat <<EOF >/run/systemd/system.attached/minimal-app0.service.d/20-portable.conf
+[Unit]
+Description=Minimal App 0
+EOF
+systemctl daemon-reload
+
 portablectl "${ARGS[@]}" attach --force --now --runtime /usr/share/minimal_0.raw minimal-app0
 
 portablectl is-attached --force minimal-app0
@@ -302,6 +317,28 @@ systemctl is-active app1.service
 
 portablectl detach --now --runtime overlay app1
 
+# Ensure --force works also when symlinking
+mkdir -p /run/systemd/system.attached/app1.service.d
+cat <<EOF >/run/systemd/system.attached/app1.service
+[Unit]
+Description=App 1
+EOF
+cat <<EOF >/run/systemd/system.attached/app1.service.d/10-profile.conf
+[Unit]
+Description=App 1
+EOF
+cat <<EOF >/run/systemd/system.attached/app1.service.d/20-portable.conf
+[Unit]
+Description=App 1
+EOF
+systemctl daemon-reload
+
+portablectl "${ARGS[@]}" attach --force --copy=symlink --now --runtime /tmp/overlay app1
+
+systemctl is-active app1.service
+
+portablectl detach --now --runtime overlay app1
+
 umount /tmp/overlay
 
 portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1