Declare Debian Package Triggers with deb-triggers
Your cache package needs to refresh whenever another package changes, and you do not want every upgrade to stall waiting for it. This guide gets you a valid DEBIAN/triggers file and a clear rule for choosing between interest-noawait and its waiting variants.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. The examples match dpkg 1.22.6, provided here by package version dpkg-dev 1.22.6ubuntu6.6.
- You need: a shell,
dpkg-debfrom the installed dpkg suite, and a writable temporary directory. - It will not touch: your system. The guide builds and inspects an archive only. It does not install it, activate a trigger on the host, or change package state, so the commands normally need no elevated privileges.
1. Decide which package owns the event
A trigger is a named hand-off between packages. Two roles, one shared name:
- Interest. The package that receives and processes the event declares an interest.
- Activation. The package whose state change causes the event declares an activation.
- The name. For an explicit trigger, both packages must agree on the exact name.
Pick a name that describes the interface and is unlikely to collide with another package. The trigger name is not a shell command and should not contain whitespace. In this example, a package that maintains a cache will process example-cache-refresh when another package changes:
$ TRIGGER_NAME='example-cache-refresh'
$ printf '%s\n' "$TRIGGER_NAME"
example-cache-refresh
Checkpoint
Write down the interested package, the activating package, and the trigger name before editing either package. A spelling mismatch creates two unrelated interfaces.
2. Add the interested package's declaration
In a source package, put the declaration in debian/triggers. When one source builds several binary packages, use debian/BINARY-PACKAGE.triggers to target one binary package. During package construction, the file becomes DEBIAN/triggers in that binary package's control archive.
For a cache refresh that is useful but not required before the activating package can be configured, use the no-wait form:
interest-noawait example-cache-refresh
File rules:
- Whitespace at the start or end of a line is ignored.
- Comments start at the first
#, and blank lines are ignored. - One directive per line. Unknown directives are errors and prevent installation.
Choosing the interest form:
interestpermits the activation to put the triggering package intotriggers-awaited.interest-awaitis the explicit spelling of that waiting behaviour.interest-noawaitprevents that wait even when the activating side asks for one.
Tip
Choose no-wait only when delaying the trigger processing cannot make the activating package unusable or leave a required invariant broken.
Checkpoint
Inspect the file as plain text. There should be one supported directive and the exact trigger name:
$ sed -n 'l' debian/triggers
interest-noawait example-cache-refresh$
3. Add activation to the changing package
In the package whose installation or removal represents the event, add the matching activation directive. The activation is associated with package state changes, not with an arbitrary file write during normal operation:
activate-noawait example-cache-refresh
dpkg activates this trigger when the package is unpacked, configured, removed, purged or deconfigured. If the package disappears while another package is being unpacked, dpkg activates it when that disappearance is noticed near the end of the unpack. Trigger processing itself does not cause another activation.
The activation forms mirror the interest forms:
activateallows the requested waiting mode.activate-awaitrequests waiting.activate-noawaitnever puts the triggering package intotriggers-awaited.
The interested package still has the final say: interest-noawait forces no-wait for activations it receives.
Warning
Do not assume that activate-await always creates a wait. It only does so when the interested package uses interest or interest-await. This pairing is the most common source of misleading package-state checks.
4. Build a harmless archive and inspect it
You can test the file without installing anything. A minimal binary package needs a control file and the triggers file under a temporary package tree:
$ workdir=$(mktemp -d)
$ mkdir -p "$workdir/pkg/DEBIAN"
$ printf '%s\n' \
'Package: example-cache' \
'Version: 1.0' \
'Architecture: all' \
'Description: Trigger declaration test package' \
> "$workdir/pkg/DEBIAN/control"
$ printf '%s\n' 'interest-noawait example-cache-refresh' > "$workdir/pkg/DEBIAN/triggers"
$ dpkg-deb --build "$workdir/pkg" "$workdir/example-cache.deb"
dpkg-deb: building package 'example-cache' in '.../example-cache.deb'.
$ dpkg-deb --control "$workdir/example-cache.deb" "$workdir/control"
$ sed -n 'l' "$workdir/control/triggers"
interest-noawait example-cache-refresh$
The temporary directory is not package state. Review the extracted control data, then remove it when you are finished:
$ rm -rf "$workdir"
Warning
That final command is destructive for the temporary directory only. If you need the archive for later review, copy it somewhere deliberate before removing the directory. Never substitute a broad path for $workdir.
5. Handle the trigger in the maintainer script
When an interested package has a pending trigger, dpkg runs its postinst with the action triggered and a space-separated list of trigger names as the second argument. Several activations can arrive together, so a shell maintainer script should handle each name independently:
case "$1" in
triggered)
case " $2 " in
*" example-cache-refresh "*) refresh-cache ;;
esac
;;
esac
- Make it repeatable. dpkg may aggregate repeated activation, and the package may need to recover work that happened while it was not configured.
- Treat the list as a hint. It is an optimisation, not permission to skip necessary initial setup.
- Keep it to package events. Do not use a trigger just because a daemon should react to every runtime event. Debian package triggers cover installation and state changes. Runtime notification needs a separate mechanism.
6. Diagnose waiting and pending states
After a real package operation, inspect package status with dpkg rather than assuming that a successful unpack means every trigger has completed:
$ dpkg-query -W -f='${Package} ${Status}\n' example-cache
example-cache install ok installed
During processing, an interested package can be triggers-pending; a triggering package can be triggers-awaited. Pending trigger work is normally attempted at the end of the relevant dpkg run. If the triggered maintainer script fails, the package can become config-failed, and dpkg will not silently retry it forever.
Recovery
If a package stays in one of these states, first read the maintainer-script error and package status. Do not run a blind reinstall or delete dpkg's database files. Re-run the normal package configuration procedure only after correcting the script or dependency problem, and keep a copy of the diagnostic output.
7. Check compatibility before publishing
Older dpkg versions reject these directives, so check the oldest supported distribution before shipping them:
- The
-noawaitvariants have been supported since dpkg 1.16.1. - The
-awaitaliases have been supported since dpkg 1.17.21.
$ dpkg-query -W -f='${Package} ${Version}\n' dpkg
dpkg 1.22.6ubuntu6.6
For a package family with older targets, either require a sufficiently new dpkg or use the older directive vocabulary supported by those targets. Record that decision in packaging documentation. An unknown trigger directive is an installation failure, not a harmless compatibility downgrade.
Done means
- Same name on both sides. The interested and activating packages use the same whitespace-free trigger name.
- Right file. Each directive is in the correct source-package or binary-package triggers file.
- No-wait is deliberate. You chose it only where deferred processing is safe.
- The archive builds. It contains the expected
DEBIAN/triggersdata. - The script copes. The
postinst triggeredpath handles names separately and can be run repeatedly. - You can recover. You checked the minimum supported dpkg version and kept a recovery path for script failures.