Continuing the discussion from Blacklist AUR paket like libgdata:
The idea of having a dummy package is good, but the use is limited to a single unwanted package.
I like puzzles
call it an academic interest ![]()
WARNING
If the intention is to avoid malware from AUR. Don’t proceed.
Although the hook will deny an AUR package, the actual building is another process and the actions defined in the PKGBUILD will not be affected by these ideas.
The usual disclaimers for experiments apply - no warranties of any kind.
![]()
![]()
Denying installation of packages from the official repo may have unexpected sideeffects
Only apply the ideas after careful consideration of eventual sideeffects.
You are the system administrator.
This is your decision.
Do not ever complain if your system fails in unexpected ways.
this is purely academic - just for the fun of it
Assumptions
I am operating in root context
sudo su
In the folder /etc/pacman.d
cd /etc/pacman.d
I will be using the micro terminal editor.
Location of files
The libalpm library expects locally defined hooks in /etc/pacman.d/hooks.
I will store the companion script in /etc/pacman.d/scripts.
To help in future maintenance - name the script after the hook it serves.
In this little exersice I create these files (the last one is the final data file)
hooks/alpm-deny.hookscripts/alpm-deny.shscripts/alpm-deny-targets
Before we begin - create the folders (assuming you are in the folder /etc/pacman.d
mkdir hooks scripts
Initial thoughts
When ever a package manager targeting a Arch Linux based system is installing a package, it will use the libalpm library.
This library provides hooks to execute actions based on defined criteria - please see
man alpm-hooks
Designing a hook
Let us look at the hook blueprint
[Trigger] (Required, Repeatable)
Operation = Install|Upgrade|Remove (Required, Repeatable)
Type = Path|Package (Required)
Target = <Path|PkgName> (Required, Repeatable)
[Action] (Required)
Description = ... (Optional)
When = PreTransaction|PostTransaction (Required)
Exec = <Command> (Required)
Depends = <PkgName> (Optional)
AbortOnFail (Optional, PreTransaction only)
NeedsTargets (Optional)
The behavior of the optional criteria is described
AbortOnFail
Causes the transaction to be aborted if the hook exits non-zero.
Only applies to PreTransaction hooks.
NeedsTargets
Causes the list of matched trigger targets to be passed to the
running hook on stdin.
Create the alpm-deny.hook
We also want the transaction to deny the installation of the given package.
Trigger section
- Trigger on installation
- Trigger type is specific package
- Target is the package we want to deny
Action section
- Description is always good
- AbortOnFail is needed as we want a signal to propagate back to the hook
- NeedsTargets this is required to display a meaningful message to the user
- We want to run the hook before the transaction takes place
- Define the script or program to execute
micro hooks/alpm-deny.hook
[Trigger]
Operation = Install
Type = Package
Target = octopi
[Action]
Description = alpm deny hook
AbortOnFail
NeedsTargets
When = PreTransaction
Exec = /etc/pacman.d/scripts/alpm-deny.sh
Create the alpm-deny.sh
micro scripts/alpm-deny.sh
#!/usr/bin/sh
# Read each target (one per line) from stdin
while IFS= read -r pkg; do
echo "ERROR: Installation of $pkg is denied by alpm-deny hook."
done
# return a non-zero exit status
exit 1
It is easy to expand which packages to deny - simply add a new Target = to the [Trigger] section - something like this
[Trigger]
Operation = Install
Type = Package
Target = octopi
Target = <package1>
Target = <package2>
Target = <package3>
Ideas For Improvments
- Change the hook to execute on all packages
- Inline a list of package to deny inside the script
- Read the array of denied packages from list of packages
Thoughts on Improvements
If we change the hook to execute on all packages, we must also change the script to return different values depending on the denied packages.
If the package passed on to the script is not in our set of denied packages the script should return 0 instead of 1.
Improved Script
Our first task is to modify the hook’s Trigger section.
Change the Target to use a * wildcard which would be all packages.
It is also possible to work with a subset e.g. using e.g. deepin*
micro hooks/alpm-deny.hook
[Trigger]
Operation = Install
Type = Package
Target = *
Then we modify script
micro scripts/alpm-deny.sh
#!/usr/bin/sh
# my attempt to learn the differences between bash and posix shell
# Arrays for example is not available in posix shell
# ------------------------------------------------------------------
# Deny list - because arrays is not a part of posix
# one element per line no spaces
# ------------------------------------------------------------------
targets="
octopi
paru
yay
"
# Convert the multiline string into a space‑separated list so we can use
# the `case` construct later. (POSIX sh does not have real arrays.)
target_list=$(printf '%s\n' "$targets" | tr '\n' ' ')
# Read every target name that pacman sent on stdin.
while IFS= read -r pkg; do
# Skip empty lines
# they can appear if the hook is run with no
# matching packages (unlikely here but harmless)
[ -z "$pkg" ] && continue
# Does $pkg exist in our target_list?
case " $target_list " in
*" $pkg "*)
echo "ERROR: Installation of package '$pkg' is denied by alpm-deny hook."
exit 1 # non‑zero → AbortOnFail triggers abort
;;
*)
# allowed – nothing to do, just continue with next line
;;
esac
done
# All packages passed the check; let pacman continue.
exit 0
Example run
# pacman -Syu yay
:: Synchronizing package databases...
core is up to date
extra is up to date
multilib is up to date
sublime-text is up to date
:: Starting full system upgrade...
resolving dependencies...
looking for conflicting packages...
Packages (13) graphviz-15.1.1-1 haskell-djot-0.1.3-1 haskell-pandoc-3.6.1-11
haskell-pandoc-lua-engine-0.4.1-16 haskell-pandoc-server-0.1.0.11-10 libxfont2-2.0.9-1
ollama-0.32.6-1 pandoc-cli-3.6.1-20 pango-1:1.58.2-1 python-argcomplete-3.7.2-1
syncthing-2.1.3-1 uv-0.12.2-1 yay-13.0.1-1
Total Download Size: 54,52 MiB
Total Installed Size: 224,64 MiB
Net Upgrade Size: 10,74 MiB
:: Proceed with installation? [Y/n]
:: Retrieving packages...
[ .... ]
:: Running pre-transaction hooks...
(1/2) alpm deny hook
ERROR: Installation of package 'yay' is forbidden by the alpm-deny hook.
error: command failed to execute correctly
error: failed to commit transaction (failed to run transaction hooks)
Errors occurred, no packages were upgraded.
Final Script
Instead of the in-lined list of packages we create a data file - place it next to the script
Create and edit the data file alpm-deny-targets
micro scripts/alpm-deny-targets
With content - example
octopi
paru
yay
Alter the script to use the file as source for denied packages
micro scripts/alpm-deny.sh
#!/usr/bin/sh
# my attempt to learn the differences between bash and posix shell
# Arrays for example is not available in posix shell
# ------------------------------------------------------------------
# Load the package names from the external file.
# Stored as /etc/pacman.d/scripts/alpm-deny-targets
# ---------------------------------------------------------------
# The file contains one name per line; we convert it into a space‑separated
# list so that later we can test membership with `case`.
# ------------------------------------------------------------------
if [ -r /etc/pacman.d/scripts/alpm-deny-targets ]; then
target_list=$(printf '%s\n' "$(sed '/^\s*#/d;/^\s*$/d' /etc/pacman.d/scripts/almp-deny-targets)" | tr '\n' ' ')
else
# if the file does not exist - there is nothing to deny and we just exist
exit 0
fi
# Read every target name that pacman sent on stdin.
while IFS= read -r pkg; do
# Skip empty lines
# they can appear if the hook is run with no
# matching packages (unlikely here but harmless)
[ -z "$pkg" ] && continue
# Does $pkg exist in our target_list?
case " $target_list " in
*" $pkg "*)
echo "ERROR: Installation of package '$pkg' is denied by alpm-deny hook."
exit 1 # non‑zero → AbortOnFail triggers abort
;;
*)
# allowed – nothing to do, just continue with next line
;;
esac
done
# All packages passed the check; let pacman continue.
exit 0
this is purely academic - just for the fun of it