Creating useful Pacman hooks

Imported from the archived forum by tbg:

I thought it would be nice to have a central thread for user created Pacman hooks. I am starting to get a bit of selection of them now, and I thought it’s time the pacman hooks got shown a little bit of love on the forum. Pacman hook usage is not widely known, so I thought it could use a little more widespread exposure.

Pacman hooks allow you to automate any function you would like executed either before or after a Pacman install/uninstall or update takes place.

Hooks included with installed packages can be found in /usr/share/libalpm/hooks.

User created hooks should be placed in /etc/pacman.d/hooks.

Any associated scripts can be placed in /etc/pacman.d/hooks.bin.

You will have to create these directories, as they are not created automatically.

Hook file names are required to have the suffix .hook.

Hooks are run in alphanumeric order of their file name, (hooks prefixed with a lower number have precedence).

Hook for Timeshift backups (2 cancelation methods)1

Timeshift Pacman Hook:

This is a revised version of my earlier timeshift hook with improved options for backup cancellation.

This hook will trigger an automatic Timeshift backup prior to installing a system upgrade. It also contains several methods to cancel the backup. This version includes automatic backup cancellation if another backup was recently made within an adjustable time frame. It also incorporates a feature that allows the cancellation of any backup with a 10 second (adjustable) countdown window via the keyboard. While the countdown is active you can cancel any backup by pressing ENTER

You may receive a popup error message when a timeshift snapshot is cancelled. The error message is irrelevant as it is only notifying about the failure of the scheduled timeshift backup (which was intended).

Preparation for creating the hook and scripts:

Create a sub-directory for the pacman hook:

sudo mkdir /etc/pacman.d/hooks

Create a sub-directory for pacman hook related scripts:

sudo mkdir /etc/pacman.d/hooks.bin

Now that we have the directories created to locate the hook and scripts we can proceed with writing them.

Timeshift Pacman Hook:

With a root capable text editor create the timeshift pacman hook:

/etc/pacman.d/hooks/50-timeshift.hook
#/etc/pacman.d/hooks/50-timeshift.hook

[Trigger]
Operation = Upgrade
Type = Package
Target = *

[Action]
Description = pre-upgrade timeshift snapshot
When = PreTransaction
Exec = /bin/sh -c "sudo -Hiu user konsole -e /etc/pacman.d/hooks.bin/killshot.sh | /etc/pacman.d/hooks.bin/timeshift.sh"


It is sometimes difficult to use variables in pacman hooks, so there are portions of code that you will need to insert your own specific info.

Exec = /bin/sh -c "sudo -Hiu user konsole -e

In the above portion of the “Exec” line, replace “user " with your own username. Replace " konsole” with the name of the terminal emulator that you use on your system. Not all terminal emulators will launch properly using the “-e” (execute) parameter. The gnome terminal may be problematic to auto-execute with this script. Unlike many other terminal emulators gnome-terminal doesn’t accept the “-e” parameter. If any knows the best method to auto-launch scripts with gnome-terminal please post the info.

This script must be used with a terminal emulator capable of accepting the “-e” (execute) parameter at launch. I do not know exactly which terminals are capable of this, but Yakuake and Konsole seem to handle this task well. You may need to experiment using different terminals to find the correct method of auto launching the script via a pacman hook.

This was a very difficult hook to get working properly with user keyboard intervention. I finally solved the problem by creating two separate scripts that require launching simultaneously via the hook. This method seems to work very well from my testing so far.

Timeshift Launch Script:

This script launches a timeshift backup automatically whenever an upgrade is initiated. The script also contains a method to automatically cancel any backup if another snapshot was taken recently. This function is to limit repeated snapshots within a short period of time. Repeated snapshots become a major annoyance when you run into an upgrade problem that you need to debug.

This script will cancel the snapshot if a prior snapshot was taken within the predetermined window of time you select. To change the time frame, replace “-mmin -60” (1hour) with another unit of time. If you would prefer the trigger to be set at two hours then simply change the time unit to “-mmin -120”.

You will need to replace the path “/run/media/user/1TB/timeshift/snapshots-ondemand” in the script with your actual timeshift backup location. The backup is stored within the “/snapshots-ondemand” sub-directory inside the main timeshift directory.

The script also triggers a small GUI popup message when the backup is beginning.

Create the script to initiate (or automatically cancel) the timeshift snapshot:

/etc/pacman.d/hooks.bin/timeshift.sh
#!/bin/bash
#/etc/pacman.d/hooks.bin/timeshift.sh
find /run/media/user/1TB/timeshift/snapshots-ondemand -mmin -60 | grep $(date +%Y-%m-%d)
if [ $? -eq 0 ]; then
    echo "timeshift backup canceled, time threshold not met"
else
    sudo -Hiu user /bin/sh -c 'DISPLAY=:0 notify-send "Timeshift_Backup_Beginning"'
        echo " "
            echo "Initiating Pre-Update Timeshift Snapshot"
            echo " "
        echo "You have 10 seconds to cancel timeshift snapshot"
    /usr/bin/timeshift --create --comments "timeshift-pacman-hook-snapshot"
fi
exit
 

Save the script, then make the script executable:

sudo chmod +x /etc/pacman.d/hooks.bin/timeshift.sh

Killshot Script:

This script allows for manual cancellation of the timeshift snapshot via keyboard intervention. It provides a 10 second (adjustable) countdown window during which you may cancel the snapshot. While the countdown is active you can cancel any backup by pressing ENTER

The number of seconds that the countdown window is open can be adjusted in this line:

for (( i=9; i>0; i--)); do

If you would like to increase the time window for cancellation to 20 seconds then adjust it as follows:

for (( i=20; i>0; i--)); do

The script also triggers a small GUI popup message when the backup is aborted.

Create the script to cancel the timeshift snapshot via keyboard intervention:

/etc/pacman.d/hooks.bin/killshot.sh
#!/bin/bash
#/etc/pacman.d/hooks.bin/killshot.sh
  echo "press any key to cancel timeshift snapshot"
      sleep 1
for (( i=9; i>0; i--)); do
    printf "\n$i seconds left to cancel snapshot  ... hit any key "
    read -s -n 1 -t 1 key
if [ $? -eq 0 ]; then
    sudo kill -2 `ps -ef|grep -i timeshift| grep -v grep| awk '{print $2}'`
        echo " "
            echo "aborting timeshift snapshot" 
      echo " "
   sudo -Hiu user /bin/sh -c 'DISPLAY=:0 notify-send "Timeshift_snapshot_aborted"'
fi
done


Save the script, then make the script executable:

sudo chmod +x /etc/pacman.d/hooks.bin/killshot.sh

This is more complicated to write than other timeshift hooks, but far more versatile in my opinion.

Hook to create a list of all installed packages1

Pacman package backup list hook:

This hook compliments the above timeshift hook nicely in any backup strategy. This hook will backup a list of both your native and alien (AUR) installed packages. This ensures you will always have an up to date list of all your packages you can reinstall from.

Why do you need this you might ask (if you have a timeshift backup)? If you suffer a catastrophic hardware failure you may really appreciate being able to reinstall all your preferred packages from a backup automatically.

Create the following hook:

/etc/pacman.d/hooks/50-pacman-list.hook

With the following content:

#/etc/pacman.d/hooks/50-pacman-list.hook
[Trigger]
Type = Package
Operation = Install
Operation = Upgrade
Operation = Remove
Target = *

[Action]
Description = Create a backup list of all installed packages
When = PreTransaction
Exec = /bin/sh -c 'pacman -Qqen  > "/home/$USER/.cache/package_lists/$(date +%Y-%m-%d_%H:%M)_native.log"; pacman -Qqem > "/home/$USER/.cache/package_lists/$(date +%Y-%m-%d_%H:%M)_alien.txt" 2> /dev/null; exit'

You will most likely wish to change the path where you store your backup lists. Adding several backup locations is even better insurance in case of a hardware failure.

You can never be “too safe” when it comes to backups.

(edit) below is an example of how you would back up to your home directory, and also to an external backup drive in the same “Exec” line:

Exec = /bin/sh -c 'pacman -Qqen  > "/home/$USER/$(date +%Y-%m-%d@%H:%M)_native.log"; pacman -Qqem > "/home/$USER/$(date +%Y-%m-%d@%H:%M)_alien.txt"; pacman -Qqem > "/run/media/$USER/Backup/package_lists/$(date +%Y-%m-%d@%H:%M)_native.log"; pacman -Qqem > "/run/media/$USER/Backup/package_lists/$(date +%Y-%m-%d@%H:%M)_alien.txt " 2> /dev/null; exit'

It is often best practice to replace “$USER” with your own user name. In most cases “$USER” will work correctly, but in some cases it may insert the root user rather that your own user name. Therefore it is sometimes better to simply ensure that your correct username is inserted as a replacement for “$USER”.

Hook to notify about orphaned packages (v.1)1

Orphaned Package Hook:

Here’s another very handy housekeeping hook.

You can use a pacman hook to notify you whenever orphaned packages are created.

To list all packages no longer required as dependencies create the following hook:

/etc/pacman.d/hooks/orphans.hook

Add the following content:

#/etc/pacman.d/hooks/orphans.hook

[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Package
Target = *

[Action]
Description = Orphaned package notification
When = PostTransaction
Exec = /usr/bin/bash -c "/usr/bin/pacman -Qtd || /usr/bin/echo '=> No orphans found.'"

You could also have the hook automatically delete orphaned packages, but automating that function is a little too risky for my liking.

Hook to notify about orphaned packages (v.2)2
[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Package
Target = *
>
>
>
[Action]
Description = Checking for orphaned packages...
Depends = pacman
When = PostTransaction
Exec = /usr/bin/bash -c 'orphans=$(pacman -Qtdq); if [[ -n "$orphans" ]]; then echo -e "\e[1mOrphan packages found:\e[0m\n$orphans\n\e[1mPlease check and remove any no longer needed\e[0m"; fi'
Hook to check for for pacnew/pacsave files2
[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Package
Target = *

[Action]
Description = Checking for .pacnew and .pacsave files...
When = PostTransaction
Exec = /usr/bin/bash -c 'pacfiles=$(pacdiff -o); if [[ -n "pacfiles" ]]; then echo -e "\e[1m.pac* files found:\e[0m\n$pacfiles\n\e[1mPlease check and merge\e[0m"; fi'
Hook to disable baloo file indexer1

The baloo file search feature has been much improved in KDE. However, it is still not my favorite search engine and I would rather have it permanently disabled. According to the ArchWiki baloo can’t be uninstalled, and it may be automatically re-enabled during a system upgrade. The ArchWiki recommends disabling baloo after any system upgrade if you do not want it run.

I decided to create a pacman hook to do this automatically after every system upgrade.

Here is the pacman hook

/etc/pacman.d/hooks/disable-baloo.hook
[Trigger]
Type = Package
Operation = Upgrade
Target = /usr/bin/baloo_file

[Action]
Description = Disable baloo file indexer after every upgrade operation
When = PostTransaction
Exec = /bin/sh -c 'killall baloo_file ; mv /usr/bin/baloo_file /usr/bin/baloo_file.bak ; echo '#!/bin/sh' > /usr/bin/baloo_file'
Hook to update grub/lsb-release3

I have some manjaro on desktop, i use one pacman hook by manjaro for create good entries in my grub
run hook only when etc/lsb-release file is updated

/etc/pacman.d/hooks/lsb-release.hook

[Trigger]
Operation = Install
Operation = Upgrade
Type = File
Target = etc/lsb-release

[Action]
Description = lsb-release change description for grub
When = PostTransaction
Exec = /usr/bin/sed -i 's/^DISTRIB_DESCRIPTION.*/DISTRIB_DESCRIPTION="Manjaro Cinnamon"/' /etc/lsb-release
Hook to fix Atheros QCA9377 firmware issue1

Atheros QCA9377 Pacman Hook

Recently I have again read reports that the Atheros QCA9377 wifi adapter is suffering breakages on system updates. This issue usually only affects those who are using kernel 4.14 (or older).

Those using kernel 4.14 (and below) need to rename or delete the Atheros firmware-6.bin for this wifi adapter to work with older kernels. When using older kernels the firmware-5.bin must be used instead.

Wifi can be repeatedly broken after a system update, if the firmware-6.bin file is upated. This can be prevented by creating a pacman hook to automatically rename the firmware-6.bin to firmware-6.bin.bak after every update.

Atheros QCA9377 Pacman Hook

With a text editor create the Pacman hook:

/etc/pacman.d/hooks/qca9377.hook
[Trigger] 
Operation = Install 
Operation = Upgrade 
Type = File 
Target = lib/firmware/ath10k/QCA9377/hw1.0/firmware-6.bin

[Action] 
Description = Rename Atheros v.6 Firmware 
When = PostTransaction 
Exec = mv /lib/firmware/ath10k/QCA9377/hw1.0/firmware-6.bin /lib/firmware/ath10k/QCA9377/hw1.0/firmware-6.bin.bak 
NeedsTargets

This hook is only necessary for those using older kernels with the QCA9377 adapter. If you update to a kernel newer than 4.14 you will need to delete the pacman hook and rename firmware-6.bin.bak to its original name.

I have not personally tested this hook (as I do not own a QCA9377 adapter), but I’m fairly certain this should prevent any firmware update breakages in the future.

Please report on this hooks effectiveness if you have tested it with your QCA9377 adapter.


1 originally posted by tbg
2 originally posted by grinner
3 originally posted by @papajoke

4 Likes

I use borg for backups, I know very little about bash scripts but I think I might be able to adapt this.

Unless someone already has and can share?

Yeah :slight_smile:

Documentation links:

Completely useless visual confirmation that update went ok :smiley:

Put it in /etc/pacman.d/hooks/ok.hook
[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Package
Target = *

[Action]
Description =
When = PostTransaction
Exec = /usr/bin/sh -c '/etc/pacman.d/hooks.bin/ok.sh'
Put this in /etc/pacman.d/hooks.bin/ok.sh and give chmod +x
#!/bin/bash
echo "
OOOOO  K  K
O   O  K K
O   O  KK
O   O  KK
O   O  K K
OOOOO  K  K
"

Nice info! Tnx for sharing.

Stepan

Check if I’m right or not but I think the Exec line for the hook to check for pacnew/pacsave files should be:

Exec = /usr/bin/bash -c 'pacfiles=$(pacdiff -o); if [[ -n "$pacfiles" ]]; then echo -e "\e[1m.pac* files found:\e[0m\n$pacfiles\n\e[1mPlease check and merge\e[0m"; fi'

i.e. "pacfiles" changed to "$pacfiles"