3

I've got a few things that I don't want to update while my graphical session is running, but would be happy to have them updated on shutdown (after my graphical session ended, while network is still up), once. So, I don't want to write a service file, enable it, and then have it run at every shutdown.

Now, I thought, OK, systemd-run to the rescue:

systemd-run \
           --property=Type=oneshot \
           --property=DefaultDependencies=no \
           --property=Requires=network.service \
           --property=WantedBy=shutdown.target \
           /usr/bin/dnf5 update -y package1 packge2…

But that fails with

Failed to start transient service unit: Dependency type WantedBy may not be created transiently.

Is there another way to this?

7
  • When you are ready to shut the computer down, run the updates, then shut the computer down. If this is a one time thing, why bother automating it? Commented Aug 3, 2024 at 0:12
  • Make use of Conflicts= and ExecStop= instead? Although I have never tested if they work in systemd-run. (Actually you might not even need Conflicts= in this case. Instead an appropriate After= is probably crucial, since you likely need the command to run early in the shutdown process. You might need to ditch DefaultDependencies=no though.) Commented Aug 3, 2024 at 1:42
  • 1
    @OrganicMarble because a computer is good at remembering to do things at the end of the day, and I'm less good. Also, I'd need to remember not to shut down regularly, but to log out of my graphical session, start a terminal session, and launch the update from there. What a hassle when I just want to leave the computer for the day! At lunch I knew exactly which packages I wanted to update, too, so I need to store that info just to retrieve it manually later. So, it is an extra step, and it deserves automation, because chances are, I'll want to do the same more often at shutdown at some point. Commented Aug 3, 2024 at 9:21
  • @TomYan which shape would that take? If a unit is not wanted by anything, what would trigger its execution? After= only specifies the order at which things are executed when they're being executed. Commented Aug 3, 2024 at 9:24
  • @MarcusMüller I mean like the service would be a RemainAfterExit=yes one 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.) (The After= is about making sure that it is "stopped" before other units that are crucial for the work.) Commented Aug 3, 2024 at 10:08

3 Answers 3

5
+200

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:

  1. 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.
  2. 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.

0
1

I've asked @TomYan to convert their comment to an answer; sadly, they didn't and so my bounty is going to fall flat. Anyways:

An approach here is to exploit the fact that units can have commands that are executed at exit; so, a service with

  • Type=oneshot
  • a dummy ExecStart (like /usr/bin/true) (or none at all if specified through unit file)
  • RemainAfterExit=true (to mark it as still alive even if the dummy has exited)
  • ExecStop= that runs the command I need
  • After=network.target to make sure this unit gets stopped before network gets stopped (it specifies that it should be started after, but stopped before)

should work, and be stopped at shutdown if started one time.

I noticed that stop timeout can be a problem, but it's not that bad a problem anymore, because starting with systemd 188, one can configure TimeoutStopSec= for a service.

7
  • 1
    +1 But this will run also on reboot, which could be annoying / unwanted. I had to set some guards in place to make the trick work only on shutdown. See here. There might be a cleaner way to do it instead of grepping stuff, however I never looked into that after getting that thing to work. So if someone knows of a better way I'd be very happy to hear about it Commented Aug 9, 2024 at 21:27
  • @kos I still have these 200 rep bounty that I need to assign to some answer that someone else wrote – if you could write your own, that'd actually be helpful, otherwise that investment would just go to waste… Commented Aug 9, 2024 at 21:30
  • I quickly edited my answer from Ask Ubuntu to make it relevant for this specific case, if you want to award the bounty I'll make sure to rebounty the question if Tom Yan happens to answer, and award the bounty to them, as technically they came in first. Could you please test my answer though? It's untested, I had to put it toghether quickly because of the bounty expiring shortly. Commented Aug 9, 2024 at 21:49
  • Also I'll make sure to fix that, but you said you don't want the service to run on every shutdown, so I'll have to convert the service to a systemd-run command, please confirm that's the case and I'll get back to that tomorrow Commented Aug 9, 2024 at 21:49
  • 1
    Done, I've tested both the systemd-run command and the service I'm proposing in the answer, they both work flawlessly, although I've tested them using a sleep command and not using an update command (it shouldn't matter as long as they're latched to the "right" target, I've done that mainly because I wanted to see the thing stuck in plymouth). Also you were right about the --now option, there was no reason to avoid it, so I included it into the answer. Let me know if that works for you Commented Aug 10, 2024 at 9:09
-1

For a one-time only update, try an at-job.

Otherwise:

For Debian-like systems, installing and configuring unattended-upgrades would be the way to go. It offers the option to install on shutdown.

The Redhat equivalent would be dnf-automatic.

Both make use of systemd-timers.

If you don't want to update specific packages you can pin/hold them.

3
  • atd has no functionality to trigger during shutdown, integrated in the systemd shutdown process, right? And dnf-automatic doesn't do anything at shutdown itself, either; I'd still need to somehow launch it then – that's the question I'm asking here! Commented Aug 9, 2024 at 10:50
  • Easy enough: it's a systemd-service, so you can create an override for it in /etc/systemd/system/dnf-automatic.service.d/override.conf to run it before shutdown. See unix.stackexchange.com/a/39604/364705 Commented Aug 11, 2024 at 9:45
  • no, I think that runs things now, and stops them after the shutdown target has been invoked (not yet run). But if you modify your answer to explain exactly what I should put where, I'd be happy to try. Commented Aug 11, 2024 at 12:11

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.