This command is based on an extrapolation and adaptation to the case in question of an answer of mine on Ask Ubuntu, which I converted to a systemd-run command. The extrapolated and adapted answer, useful to understand the reasoning behind the command and useful to set this up as permanent service rather than as a transient unit, is reported down below.
Note that this will run on poweroff and won't run on reboot. This is intentional. If this is undesired and you want to run this both on poweroff and on reboot, simply replace the ExecStop property with just dnf5 update -y package1.
systemd-run \
--property="ExecStop=sh -c 'systemctl list-jobs | grep -q \"poweroff.target.*start\" && dnf5 update -y package1'" \
--property=RemainAfterExit=true \
--property=TimeoutStopSec=infinity \
--property=After=network-online.target \
true
Replace package1 according to needs.
What my research has taught me is that:
- It's hard to latch the service to the right point in the poweroff / reboot chain if you're approaching the problem in terms of "order in which services go down in the poweroff / reboot chain"; there's just too much to keep track of. The trick here, is to approach the problem in terms of "order in which services go up in the startup chain", and to latch a
oneshot service right after network-online.target has gone up, at the same time marking it as active using RemainAfterExit=true and providing it with an ExecStop action which will be "naturally" triggered when the system is going down, just right before the network goes down.
- There's no super-clean way to determine if the system is going down for poweroff or for reboot; however, this can be done reliably by checking which systemd special targets are active during the poweroff / reboot sequence; in this case,
poweroff.target will be active only in case the system is going down for poweroff.
So, putting everything together, this could be done by creating a service /etc/systemd/system/update.service (the name of the file and the Description and ExecStop fields, of course, may be adjusted; make sure the file is owned by root:root and has 644 / -rw-r--r-- permissions):
[Install]
WantedBy=multi-user.target
[Service]
ExecStop=sh -c 'systemctl list-jobs | grep -q "poweroff.target.*start" && dnf5 update -y package1'
RemainAfterExit=true
TimeoutStopSec=infinity
[Unit]
After=network-online.target
Description=update
Once done, run sudo systemctl enable --now update.service to enable the service.
TimeoutStopSec=infinity is obviously needed in case of an update, but it can be changed in case you want to use this for something else.
Conflicts=andExecStop=instead? Although I have never tested if they work insystemd-run. (Actually you might not even needConflicts=in this case. Instead an appropriateAfter=is probably crucial, since you likely need the command to run early in the shutdown process. You might need to ditchDefaultDependencies=nothough.)After=only specifies the order at which things are executed when they're being executed.RemainAfterExit=yesone that starts e.g./usr/bin/true. When it is "stopped" because of the shutdown process / conflict, you desired command will run. (Certainly you will need to make sure the unit stop timeout is something long enough.) (TheAfter=is about making sure that it is "stopped" before other units that are crucial for the work.)