Trigger systemd Work After an Offline /usr Update
An offline update that replaces /usr/ leaves a gap: nothing has told systemd that /etc/ or /var/ might now need follow-up work. systemd-update-done.service closes that gap. This guide shows how it works and how to make your own unit run in the same update window, ending with a service that runs only while work is needed, then lets systemd mark it done.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about 10 minutes. You need a systemd host and permission to read unit files. The examples that inspect state are ordinary commands. Starting the service or changing timestamps needs root and can alter boot-time update behaviour.
1. Check the installed version and unit
The installed manpage on this host is from systemd 255.4-1ubuntu8.17. The service is a static, one-shot unit, so there is normally nothing to enable. Inspect the unit and its current condition:
systemctl --version | head -n 1
systemctl cat systemd-update-done.service
systemctl status systemd-update-done.service --no-pager
On this machine, the unit contains ConditionNeedsUpdate=|/etc and ConditionNeedsUpdate=|/var. It runs after local-fs.target and before sysinit.target. A status of inactive (dead) with a start condition unmet is normal when both stamp files are already current.
Checkpoint
Continue once the unit is loaded and you understand whether its condition is currently met. Do not enable it; its boot ordering and conditions are supplied by the unit itself.
2. Understand the two stamp files
The helper compares the modification time of the /usr/ directory with /etc/.updated and /var/.updated. If a stamp is older than /usr/, that area is considered to need an update. When the service completes, it advances each stamp to the /usr/ timestamp, unless the stamp is already newer.
The timestamp lives in the file metadata and, in current upstream systemd, also in the file contents for filesystems that cannot retain full timestamp precision. Treat these files as system-managed markers: do not edit their contents or delete them as a routine diagnostic.
stat -c '%n %y' /usr /etc/.updated /var/.updated
Expected output is three paths and timestamps; the exact dates vary. A stamp older than /usr is evidence that the matching area may need post-update work, not proof that a particular package is broken.
3. Make your own service update-aware
For a service that migrates configuration or data after an offline /usr/ update, add the condition and ordering to its unit. Use a drop-in or a unit file owned by your application. The essential shape:
[Unit]
Description=Apply the application update
Before=systemd-update-done.service
ConditionNeedsUpdate=/etc
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/apply-application-update
- Use
ConditionNeedsUpdate=/varinstead when the work is driven by data under/var/. If both areas matter, add both conditions: a unit needs all of its conditions to pass, so choose deliberately rather than adding both out of habit. Before=systemd-update-done.serviceis the important ordering rule. Without it, the marker service could advance the stamp before your service checks it. The condition decides whether your unit is eligible; ordering decides which unit acts first.
After installing or changing the unit, ask systemd to read it again and inspect the result:
sudo systemctl daemon-reload
systemctl cat apply-application-update.service
systemctl show apply-application-update.service -p Before -p ConditionResult
Replace apply-application-update.service with the real unit name. ConditionResult describes the most recent condition evaluation, not a guarantee the service has run successfully.
4. Mark an offline update at the right time
The update mechanism must advance /usr/ after changing its contents, which matters for nested files: changing a file below /usr/ does not necessarily change the directory's own timestamp. An update process whose post-update work is already complete should not touch the timestamp just to make this mechanism pass; use it only when later boot work is genuinely required.
For an offline updater whose work is complete and whose next boot must run the application migration, the final timestamp operation is typically:
sudo touch /usr
This changes system state and should be done only by the update workflow, after its files are in place. It does not run your migration immediately. On the next boot, systemd sees /usr/ as newer than the relevant stamp, allows the ordered service to run, and then systemd-update-done.service advances the markers.
Warning
Do not use touch /usr as a general repair command or a substitute for understanding your package manager. It can make every unit using ConditionNeedsUpdate= eligible on the next boot.
5. Verify without forcing a production update
First check whether the service was skipped by a condition or failed while running:
systemctl status systemd-update-done.service --no-pager --full
journalctl -b -u systemd-update-done.service --no-pager
A skipped service has a condition message and may have no journal output. A failed service has an error state and a journal entry. For your own unit, check status and journal the same way:
systemctl status apply-application-update.service --no-pager --full
journalctl -b -u apply-application-update.service --no-pager
Do not repeatedly start the marker service on a live host just to get output: its helper writes under /etc/ and /var/. On systemd 255, the installed helper has no useful alternate-root workflow, and running it directly as an unprivileged user fails with permission errors. Newer upstream documentation adds --root= in version 258, so do not copy that option to this system.
Common traps
- The service is inactive. Check its condition first; this is often the successful steady state, not a fault.
- Your service never runs. Confirm the update process actually changed
/usr/, then updated its directory timestamp. CheckBefore=systemd-update-done.serviceand the relevantConditionNeedsUpdate=path. - The timestamp looks right but the condition is forced. The kernel command-line option
systemd.condition-needs-update=overrides file timestamp checks, and stays effective until a later reboot without it. Check the boot command line before changing files. - The service ran too early. Add explicit ordering before the marker unit; the condition alone does not establish ordering.
If an update was interrupted, repair or complete it using its own documented recovery procedure, then arrange the correct /usr/ timestamp and reboot through the normal path. There is no general undo for a stamp already advanced: rerun the required migration explicitly, or restore the update workflow from a known-good backup.
Done means
- You confirmed the installed systemd version and inspected the static marker unit.
- You can explain how
/usr,/etc/.updatedand/var/.updateddetermine eligibility. - Your post-update unit uses the right
ConditionNeedsUpdate=path and orders itself before the marker service. - Your updater touches
/usr/only after the offline update is complete and genuinely needs follow-up work. - You verified status and journal output without repeatedly mutating production stamp files.