Run script after update?

Is there any way to run a user script after OSMC has completed an update?

Alternatively, if I run a script at each time the system boots, is there any way that the script can check if the most recent reboot was to install an update?

Context: I run a few minor modifications to Confluence. After each update I want to ensure my modifications are still applied, and if not, reapply them. I have a script that does this and works well. At the moment it runs via systemd prior to mediacenter loading. However, I don’t need it to run every time the system boots, only those reboots that applied an OSMC update (or even more specifically, system updates that updated the specific package that contains skin.confluence).

Thoughts welcome.

Not easily.

What does the script do? You might not NEED to run the script every time, but if you can, then that is the easiest solution.

OK, fair enough, I’ll just run it every time. It’s no big deal.

It it were possible to run a script after an update some time in the future I could push a notification via Pushover that an update had been applied, which would be nice (but by no means required).

Well, updates from now on will bump the OSMC version, so you could simply check for a change in that and finish the script only if it is different.

That WOULD require you to keep a record of the last version in a file somewhere.

This is relatively trivial in python, but might be more difficult in bash?

Use ‘diff’ to check for difference to /etc/os-release

1 Like

Perfect, that’s what I need, thanks Sam. I’ll write a script that pushes a notification on boot when VERSION_ID has changed.

Why don’t you fork Confluence and rename it so that Kodi treats it as a different Skin ?

Yes, that’s another option. After Isengard goes final I may do that.

Hi @ashtonaut, I’m really interested in your script to pushover notification after automatic system update :smiley:
Have you move forward with this ?

Sure. First, set up a Pushover account and create a new app on the Pushover website called ‘OSMC’ or something similar.

Second, here’s the script that I use (/home/osmc/push.sh) to push notifications from the command line:

    #!/bin/bash
    
    # Uses the Pushover API to send the first command line parameter as a push notification
    
    curl -s \
      --form-string "token=YOURAPPTOKEN" \
      --form-string "user=YOURUSERTOKEN" \
      --form-string "message=$1" \
      https://api.pushover.net/1/messages.json > /dev/null

Second, create the file /etc/system/system/mediacenter.service.d/local.conf with the following content (this triggers the script when OSMC starts up):

    [Service]
    ExecStartPre = /home/osmc/updatecheck.sh | systemd-cat -t updatecheck

Finally, here is the updatecheck.sh file content:

#!/bin/bash

# Check if OSMC has just been updated
OLDVER=$(cat /home/osmc/versionid.txt)
NEWVER=$(cat /etc/os-release | grep VERSION_ID | awk -F\" '{print $(NF-1)}')

echo "Checking if OSMC has been updated..."

if [ "$OLDVER" != "$NEWVER" ]; then
  echo "OSMC has been updated, pushing notification..."
  /home/osmc/push.sh "OSMC has been updated to $NEWVER"
  echo $NEWVER > /home/osmc/versionid.txt
  exit 0
fi

echo "No update detected"

OSMC hasn’t been updated since I set this up, but I think it should all work…

That is not going to work, because you are checking for /etc/os-release but we won’t necessarily update this version number for all updates - only for the regular monthly updates.

Auto updates will only be pushed once per month though?

Is there an alternative file I could check?

Edit: actually, as this script only fires on start or restart of the mediacenter process, it won’t pick up updates that don’t restart the process, so I’m happy that it will only advise on major updates that involve a reboot.

@ashtonaut

as apt is used for updates/upgrades, create file /etc/apt/apt.conf.d/99-post-upgrade with this content:

APT::Update::Post-Invoke-Success {"XXXXXXX";};
APT::Update::Post-Invoke {"YYYYYYY";};
Dpkg::Post-Invoke {"ZZZZZZZZ";};

during apt single run, dpkg is spawned for each .deb package. that means the last line (“dpkg::postinvoke”) would be started for each single installed package, second line once an apt run (regardless of end-status) and 1st line once per run - only if finished successfully.
XXX/YYY/ZZZ are “commands” started in a shell - that means it can be from single command to very complex programming.

basically this would be answer to your question, but I think once there is deb, anything like this is pure complication and unnecessary complex (the “concept” of checking for update + restoring).

deb allows you to deliver same folder/files like another package in the system already installed. that means that you should simply bundle “your changes” into .deb pkg, set this .deb with param “Replaces: xxxxxxx” and install it.
those files will never ever be updated by package “xxxxxxxx” again.

1 Like

This looks very interesting - thanks.

I’ve gone the custom skin route so no longer need to change skin files post update.

I am still interested in pushing a notification when updates have been applied and it sounds like this apt idea is worth trying. Cheers

@ashtonaut

you can start a test by setting this:

APT::Update::Post-Invoke {"env > /root/APT-GET.environment.txt 2>&1";};

you will see all the variables (with apt session info) which are available for use in scripts.
if you “debug” post-dpkg event this way, for sure there will be detailed info about each deb, like name, version… etc

@DBMandrake : We could use this to know if it’s safe to start Kodi again for users upgrading with apt-get via commandline

Yes I have considered this approach before - we would also need to check whether the user was connected to a local tty or not - if they were, we should not restart kodi over the top of a local console login, only if they are updating via SSH.

We also need to check ‘if systemctl is-enabled’ before restarting Kodi in case they have Kodi disabled. It can be done but I’m not sure if the extra complication is worth the hassle. Without using an external script we can only use a one-liner and have to be very careful to avoid any errors or it can break apt-get entirely.

Here is a Post-Invoke script that we already use as an example of a one-liner:

This doesn’t seem to be the case. During my testing of the samba restart hook shown in my post above I found that Dpkg::Post-Invoke actually only runs once during an apt-get dist-upgrade session where multiple packages are upgraded at once. This was proven by including an echo to console line in the script during my testing. (since removed)

This is probably because the hook is run after the dpkg configure stage, and normally all dpkg configure stages are run together in a batch near the end of the apt process. The only case where you might have a dpkg configure followed by the installation of another package is if you are upgrading a package with a “Pre-Depends” dependency, which is not very common. (Even then I have not observed this, as we actually have a Pre-Depends in our smb-app-osmc package, yet I still only see the hook being run once)

@DBMandrake

aren’t those tasks responsibility of per pkg postinst scripts ? (or claiming interest for triggers ?)
for this kind of usage it is really not meant.

((systemctl reload-or-try-restart samba.service should do the same without the checks - but I assume the “samba” was just an example ???))

if you want to achieve KODI (or any other service / app) restart (or a maintenance session in general), use triggers. beside libc/glibc update I can’t imagine why restart would be needed (beside KODI update itself) - so will “demontrate” on a generic event “system updated”.
(otherwise only very specific cases are used as reason to restart a process (events generated by other installed packages or if necessary new defined)).

it works this way:

  • add new control file named [packagename].triggers (to be put into DEBIAN/ like the others)
  • in the file one can specify “activate XXXXXX” or “interest XXXXXX”. activate causes dpkg to emit trigger named XXXXXXX - for all packages with defined “interest XXXX” .postinst script will be run with $1 = triggered.
  • activate/interest lines in .triggers control file have no restriction (on count or combinations). interest line can specify simply a name of trigger, but also a PATH (including wild-marks). in case PATH is specified, any change to the PATH will trigger the process (so .postinst with param “triggered”).

back to the problem:

  1. any complicated scripting you puts into .postinst behind $1 == triggered
  2. kodi.triggers file will contain “interest apt-success” (or “interest /usr/local/kodi” would end up with the same result)
  3. but if you define apt-success as triggering event, then in the APT::Update::Post-Invoke-Success {"XXXXXXX";}; you would just put
dpkg-trigger --no-wait "apt-success"

that way you can ‘hook’ onto apt run result any number of packages each with any code you want. you can even trigger the “trigger” from postinst script of the application itself. so deb kodi would call dpkg-trigger from postinst and $1 == configure. trigger will be queued, then executed at later time. also it will run just once regardless of how many times (or how many packages) it was called (so KODI restart just once without any additional logic to code).

(((I’m writing all this only because the system of triggers is almost not documented and can be very usefull)))

regarding the dpkg-pos::invoke - my bad If I was wrong. dpkg is spawned for each one single package so (wrongly) assumed the post-invoke will act accordingly (be started at each dpkg process finish).

The issue is that Samba is a special case, and does not come with a native systemd service, only with legacy sys v init scripts, also samba is broken into two separate services - smbd and nmbd.

Our service manager in My OSMC expects a single, proper systemd service and can’t deal with interrogating and controlling a sysv service especially broken into two services so we divert the original init scripts and add a meta-service:

The original init scripts are “disabled” during installation of samba so they don’t start on boot, and it is up to the meta service to start samba on boot if it is enabled. The status of this meta service is queried to see whether samba is enabled.

The problem comes about when the debian samba package is upgraded - the sys v init script will be stopped by the package upgrade scripts but because the smbd and nmbd init services are marked as disabled they will not be automatically restarted, thus an upgrade of samba would stop samba until a reboot.

This is the reason for 99-samba-update-restart - it’s not ideal but it does solve the problem.

No it doesn’t - according to documentation “Reload one or more units if they support it. If not, restart them instead. This does nothing if the units are not running.” - at the point this command runs, the smbd service it not running - this is why we have to run the command in the first place to restart the service.

The script that I run in the Dpkg post step checks checks that (a) the samba.service is enabled (b) smbd.service (actually the sys v init script for smbd) is not running, if both are true, restart the samba meta-service, which in turn restarts smbd and nmbd services.

We check if the service is enabled because we should not restart samba on upgrade if the user has disabled it in the service manager. We check that smbd is not already running so that we do not unnecessarily restart it when other packages are upgraded.

I assumed the same as well from documentation I had read but when tested I only saw it run once.

As I say I think dpkg configure is run for all packages (*) at once with multiple package names passed at once on the dpkg command line, thus there is only one dpkg configure executed to configure multiple packages in a row.

The normal upgrade process of multiple packages is:

  1. All package pre-scripts are run
  2. All packages are unpacked
  3. All package post-scripts are run

(*) The exception to this is where there are packages with Pre-Depends, where step 1 for package A that pre-depends on package B is delayed until after step 3 of package B.

PS thanks for the hints on triggers - I have looked into them a little bit but as you say they are not well documented so I haven’t had a chance to study them in detail and see what real world use cases they are useful in.