Control: tags -1 + patch

Attached is a debdiff against 1:10.5.2-1 that fixes this.

The reason the daemon is never restarted is explicit in debian/rules:

  override_dh_installinit:
        dh_installinit --name=dhcpcd --no-start --no-stop-on-upgrade 
--no-restart-after-upgrade

  override_dh_installsystemd:
        dh_installsystemd --name=dhcpcd --no-start --no-stop-on-upgrade 
--no-restart-after-upgrade
        dh_installsystemd --name=dhcpcd@ --no-start --no-stop-on-upgrade 
--no-restart-after-upgrade

dh_installsystemd(1) notes that --no-stop-on-upgrade "has the side-effect of
not restarting the service as a part of the upgrade", and --no-start
suppresses the start/restart snippet outright, so the generated postinst
contains only the enable logic.

I assume those flags are deliberate -- a DHCP client is exactly the sort of
daemon you do not want bounced in the middle of an unattended upgrade -- so
rather than change debian/rules I added a debian/dhcpcd.postinst that restarts
the service only when it is already running.  Fresh installs, and systems
where the admin has stopped or masked the unit, are unaffected, so the intent
of --no-start is preserved.  It follows the same #DEBHELPER# pattern as the
existing debian/dhcpcd.preinst.

If you would rather have debhelper handle it, dropping the three flags in
favour of plain --restart-after-upgrade gives the same result with less code,
at the cost of also starting the daemon on fresh installs.  I went with the
postinst because it changes strictly less behaviour, but I have no attachment
to either form.

TESTING

Built the package with and without the change and ran both from the same
starting state: a VM running the 1:10.3.2-6 manager, interface configured by
ifupdown (iface enp1s0 inet dhcp), on Debian forky/sid amd64.

  Case 1, stock 1:10.5.2-1
    before upgrade: manager=dhcpcd-10.3.2  pkg=1:10.3.2-6
    after  upgrade: manager=dhcpcd-10.3.2  pkg=1:10.5.2-1
    control command: HUNG, SIGKILLed after 20s (exit 137)

  Case 2, patched 1:10.5.2-2
    before upgrade: manager=dhcpcd-10.3.2  pkg=1:10.3.2-6
    after  upgrade: manager=dhcpcd-10.5.2  pkg=1:10.5.2-2
    control command: returned in 0s (exit 0)
    network after the restart: enp1s0 UP 172.31.0.122/24 (unchanged)

  Case 3, patched package but dhcpcd.service stopped beforehand
    before upgrade: dhcpcd.service is-active=inactive
    after  upgrade: dhcpcd.service is-active=inactive

The restart does not disturb the running configuration: /etc/dhcpcd.conf ships
"persistent", so the addresses and routes stay up across it, as Case 2 shows.

Finally, the user-visible symptom, upgrading from 1:10.3.2-6 with the patched
package and then rebooting:

  Sep 06 10:23:49 testy systemd-logind[443]: System is rebooting.
  Sep 06 10:23:49 testy systemd[1]: Stopping networking.service...
  Sep 06 10:23:49 testy ifdown[5826]: sending commands to dhcpcd process
  Sep 06 10:23:49 testy systemd[1]: networking.service: Deactivated 
successfully.
  Sep 06 10:23:49 testy systemd[1]: Shutting down.

All in the same second, against the roughly three minutes and a SIGKILL
reported originally.

ONE THING I DID NOT COVER

debian/rules passes the same flags for [email protected].  A running
dhcpcd@<iface>.service instance has the identical mismatch after an upgrade,
but restarting per-interface instances is more disruptive than restarting the
manager, and it is not the case I hit, so I left it alone.  You may want to
handle it too.

UPSTREAM

I also reported the other half of this -- that the client blocks in read(2)
forever instead of timing out -- upstream, with a patch:

  https://github.com/NetworkConfiguration/dhcpcd/issues/723
  https://github.com/NetworkConfiguration/dhcpcd/pull/724

That change makes a mismatched pair recover after 5 seconds with a warning
instead of hanging, but it only helps once the client side is new enough to
contain it; restarting the daemon on upgrade is what actually prevents the
mismatch from arising on Debian.
diff -Nru debpkg-orig/debian/changelog debpkg/debian/changelog
--- debpkg-orig/debian/changelog	2026-08-17 18:13:55.000000000 +0200
+++ debpkg/debian/changelog	2026-09-06 10:18:54.527241166 +0200
@@ -1,3 +1,14 @@
+dhcpcd (1:10.5.2-2) UNRELEASED; urgency=medium
+
+  * debian/dhcpcd.postinst: restart dhcpcd.service on upgrade when it is
+    already running.  debian/rules disables stopping and restarting across
+    upgrades, which left the running manager on the old binary while
+    ifup/ifdown exec'd the new client; a >= 10.5 client blocks forever on the
+    control socket waiting for a reply a < 10.5 manager never sends, hanging
+    ifdown(8) and adding ~3 minutes to the next shutdown.  (Closes: #1146835)
+
+ -- Thomas Glanzmann <[email protected]>  Sun, 06 Sep 2026 10:20:00 +0200
+
 dhcpcd (1:10.5.2-1) unstable; urgency=medium
 
   * New upstream version.
diff -Nru debpkg-orig/debian/dhcpcd.postinst debpkg/debian/dhcpcd.postinst
--- debpkg-orig/debian/dhcpcd.postinst	1970-01-01 01:00:00.000000000 +0100
+++ debpkg/debian/dhcpcd.postinst	2026-09-06 10:18:47.600950942 +0200
@@ -0,0 +1,31 @@
+#!/bin/sh
+# As per Debian bug #1146835.
+set -e
+
+#DEBHELPER#
+
+# debian/rules passes --no-start --no-stop-on-upgrade --no-restart-after-upgrade
+# to dh_installinit and dh_installsystemd, so an upgrade leaves the running
+# manager on the old binary while ifup/ifdown start exec'ing the new client.
+# That pairing deadlocks: a client from 10.5 or later sends its command over
+# the control socket and then blocks in read(2) waiting for a reply that a
+# manager older than 10.5 never sends.  ifdown(8) therefore never returns, and
+# at shutdown networking.service's ExecStop hangs until systemd SIGKILLs it,
+# costing about three minutes on the first reboot after the upgrade.
+#
+# Restart the daemon so that the manager and the client can never diverge.
+# Only do so when it is already running, which keeps the intent of --no-start
+# for fresh installs and for systems where the admin has stopped or masked it.
+if [ "$1" = "configure" ] && [ -n "$2" ]; then
+	if [ -d /run/systemd/system ]; then
+		if systemctl --quiet is-active dhcpcd.service 2>/dev/null; then
+			deb-systemd-invoke restart dhcpcd.service >/dev/null || true
+		fi
+	elif [ -x /etc/init.d/dhcpcd ]; then
+		if invoke-rc.d dhcpcd status >/dev/null 2>&1; then
+			invoke-rc.d dhcpcd restart || true
+		fi
+	fi
+fi
+
+exit 0

Reply via email to