Package: init-system-helpers
Version: 1.69+nmu1
Severity: normal
Tags: patch
User: [email protected]
Usertags: origin-ubuntu stonking ubuntu-patch

Dear Maintainer,

    I have 2 packages that provide that same systemd unit file
    and when I try to replace one by the other, the systemd unit
    becomes disabled since the link has been removed on the purge
    of the second package.

    The current behavior of deb-systemd-helper purge:

    If the unit files are provided by 2 packages (that Replaces and
    Conflicst each other). Purging the first package while the second
    is install removes all the links and break the first package.
    
    This commit propose a more conservative purging behavior by
    keeping symlinks during purge when their target unit file still exists,
    preventing one package's purge from disabling a unit still provided
    by another installed package.

  *  deb-systemd-helper: preserve links to existing units during purge


Thanks for considering the patch.


-- System Information:
Debian Release: trixie/sid
  APT prefers noble-updates
  APT policy: (500, 'noble-updates'), (500, 'noble-security'), (500, 'noble'), 
(100, 'noble-backports')
Architecture: amd64 (x86_64)

Kernel: Linux 7.0.0-28-generic (SMP w/16 CPU threads; PREEMPT)
Kernel taint flags: TAINT_PROPRIETARY_MODULE, TAINT_OOT_MODULE
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages init-system-helpers is related to:
pn  insserv  <none>
diff -Nru init-system-helpers-1.69+nmu1/script/deb-systemd-helper 
init-system-helpers-1.69+nmu1ubuntu1/script/deb-systemd-helper
--- init-system-helpers-1.69+nmu1/script/deb-systemd-helper     2022-07-13 
21:55:56.000000000 +0200
+++ init-system-helpers-1.69+nmu1ubuntu1/script/deb-systemd-helper      
2026-08-23 00:45:26.000000000 +0200
@@ -447,19 +447,26 @@
     assertdpkgroot($dsh_state, "remove_links");
     assertnotdpkgroot($service_path, "remove_links");
 
-    if (is_purge()) {
+    # If the unit file still exists on disk, another still-installed package
+    # also ships it (e.g. identical shared conffiles, or reached via Also=
+    # from a package other than the one being purged); don't wipe out its
+    # enabled-state bookkeeping just because we are purging.
+    my $can_purge = is_purge() && ! -f "$dpkg_root$service_path";
+
+    if ($can_purge) {
         unlink($dsh_state) if -e $dsh_state;
     }
 
     # Also disable all the units which were enabled when this one was enabled.
     for my $link (@entries) {
         # Delete the corresponding state file:
-        # • Always when purging
+        # • Always when purging (and no other package still ships the unit)
         # • If the user did not disable (= link still exists) the service.
         #   If we don’t do this, the link will be deleted a few lines down,
         #   but not re-created when re-installing the package.
         assertdpkgroot($link, "remove_links");
-        if (is_purge() || -l $link) {
+        next if is_purge() && -e $link;
+        if ($can_purge || -l $link) {
             my $link_state = $link;
             $link_state =~ 
s,^\Q$dpkg_root\E/etc/systemd/$instance/,$enabled_state_dir/,;
             unlink($link_state);

Reply via email to