English
The role of the prerm script and the correct way to use it

"When uninstalling a package, the data was lost!" — This is the most common catastrophic mistake beginners make when packaging.
prerm(pre-removal) is a Debian package in before being removed The executed script is responsible for completing cleanup work before the file is deleted. However, because it involves the sensitive operation of "deletion", an incorrect prerm The script may cause:
Business data was accidentally deleted
The dependency package is corrupted.
The upgrade process cannot be rolled back.
This article will provide an in-depth interpretation of prerm all trigger scenarios of it, and provide production-grade security practices.
What is prerm?
prerm is in the Debian package Execute script before uninstalling, run before the package's files are deleted from the system. Its responsibilities include:
Stop running services (graceful shutdown)
Unregister systemd service (
disable)Clean up temporary files or cache
Yield resources when handling dependency conflicts
📌Naming convention: Script is located at debian/ Under the directory, after packaging, it is installed to /var/lib/dpkg/info/<package>.prerm.
Trigger scenarios for prerm (more complex than postinst)
| Scene | first parameter | The second parameter | Explanation |
|---|---|---|---|
| Package uninstallation | remove | None | User-initiated uninstall (keep configuration files) |
| Version upgrade | upgrade | New version number | Upgrade to the new version, and the old version executes prerm |
| dependency conflict | deconfigure | Configured package name | most complex: The package was forcibly deconfigured due to dependency issues. |
| Installation failed, rolling back | failed-upgrade | Old version number | Roll back to the old version after a failed upgrade |
⚠️Key point:deconfigure This is a scenario unique to prerm; many beginners completely ignore it, leading to a chaotic system state in complex dependency scenarios.
Standard template for prerm
Basic template (recommended)
bash
#!/bin/sh
set -e
case "$1" in
remove)
# User uninstall: stop the service, but do not delete data
;;
upgrade)
# Upgrade to the new version: gracefully stop the old version service
;;
deconfigure)
# Dependency conflict: package forcibly deconfigured
# This is the most complex scenario and requires special care.
;;
failed-upgrade)
# Upgrade failure rollback: do nothing, let the old version recover
;;
*)
echo "prerm called with unknown argument: $1" >&2
exit 1
;;
esac
exit 0Hands-on: Writing a prerm for a Go application
Continuing from Chapter One's myapp Go service, we need to complete the following operations before uninstalling:
Stop the running service
Deregister the systemd service (only during a complete uninstall)
Retain all business data(Only delete itself, do not delete user data)
Complete prerm script
bash
#!/bin/sh
set -e
PKGNAME="$DPKG_MAINTSCRIPT_PACKAGE"
case "$1" in
remove)
# User uninstall: stop services but retain all data and configuration files
# Use deb-systemd-invoke to gracefully stop
if [ -x /usr/bin/deb-systemd-invoke ]; then
deb-systemd-invoke stop myapp.service >/dev/null 2>&1 || true
fi
# Disable the service (but keep the configuration file)
if [ -x /usr/bin/deb-systemd-helper ]; then
deb-systemd-helper disable myapp.service >/dev/null 2>&1 || true
fi
;;
upgrade)
# Upgrade to a new version: gracefully shut down the old version
# Note: Do not disable the service here, otherwise the new version will not be able to be enabled.
if [ -x /usr/bin/deb-systemd-invoke ]; then
deb-systemd-invoke stop myapp.service >/dev/null 2>&1 || true
fi
;;
deconfigure)
# ⚠️ Forced resolution configuration caused by dependency conflicts
# This is the trickiest scenario: other packages depend on us, but that package has been uninstalled.
# Scenario example: myapp depends on mysql, but when mysql needs to be upgraded, the versions are found to be incompatible.
# At this point, myapp will be deconfigured until the conflict is resolved.
# Handling method: only stop the service, but do not perform any destructive operations.
if [ -x /usr/bin/deb-systemd-invoke ]; then
deb-systemd-invoke stop myapp.service >/dev/null 2>&1 || true
fi
# ❌ Error: Do not delete data or disable services in deconfigure
# Because after deconfigure the package is still installed, just temporarily unavailable.
;;
failed-upgrade)
# Rollback on upgrade failure: do nothing
# The system will automatically revert to the old version, and the old version's files are still there.
# We only need to let the old version of postinst handle the recovery logic.
;;
*)
echo "prerm called with unknown argument: $1" >&2
exit 1
;;
esac
# Call the code automatically generated by debhelper.
if [ -x /usr/share/debconf/confmodule ]; then
. /usr/share/debconf/confmodule
fi
exit 0Key Best Practices
1. Distinguish between remove and purge
prerm only in remove Stage operation,purge(Thoroughly remove) by postrm Process.
bash
# ❌ Error: Removing configuration files in prerm
remove)
rm -rf /etc/myapp # The configuration file has been deleted, and users cannot retain it.
# ✅ Correct: prerm only stops the service and does not delete any files.
remove)
deb-systemd-invoke stop myapp.service
# Data is retained and is only deleted during the purge phase of postrm.Principle:prerm Responsible for "stop",postrm Responsible for "deletion".
2. Use deb-systemd-invoke instead of calling systemctl directly
bash
# ❌ Error: Calling systemctl directly
systemctl stop myapp.service
# ✅ Correct: use deb-systemd-invoke
deb-systemd-invoke stop myapp.serviceReason:
deb-systemd-invokeWill handle it correctly--no-restart-on-upgradeand other strategiesat
deconfigureBehavior is safer in the scenario.Avoid errors in container or chroot environments
3. Do not disable the service during upgrade
bash
# ❌ Error: Disable the service during upgrade
upgrade)
systemctl stop myapp.service
systemctl disable myapp.service # The new version will not be automatically enabled.
;;
# ✅ Correct: stop only, do not disable
upgrade)
deb-systemd-invoke stop myapp.service
# The new version will re-enable it in postinst.
;;4. Be especially careful in deconfigure scenarios.
deconfigure is the most easily overlooked scenario. It occurs in:
Package A depends on Package B
Package B is about to be upgraded, but the new version is incompatible with Package A.
dpkg decides to first "deconfigure" package A, freeing up the dependency relationship.
After package B is upgraded, reconfigure package A.
bash
deconfigure)
# Only stop the service; do not perform any destructive operations.
deb-systemd-invoke stop myapp.service >/dev/null 2>&1 || true
# ❌ Don't do:
# - Delete any files
# - Disable systemd services
# - Delete user
# - Clean up the database
;;Common Pitfalls and How to Avoid Them
Pitfall 1: Deleting user data in prerm
bash
# ❌ Catastrophic error
remove)
userdel myapp
rm -rf /var/lib/myapp # All user data is gone!Correct approach: Data provided by postrm at purge Stage processing,prerm Only responsible for stopping the service.
Trap 2: Use set -e But the command failed.
bash
# ❌ If the service is not running, the stop command will fail, causing the installation to be interrupted
set -e
systemctl stop myapp.service
# ✅ Correctly handle failure cases
set -e
systemctl stop myapp.service || truePitfall 3: Deleting configuration files in deconfigure
bash
# ❌ Error
deconfigure)
rm -rf /etc/myapp # Delete the configuration during deconfiguration; when reconfiguring, the configuration is found to be lost.The correct approach:deconfigure It is a temporary state, the package will be reconfigured afterward, do not perform any irreversible operations.
Pitfall 4: Long blocking during upgrade
bash
# ❌ Error: wait for the service to stop completely
upgrade)
systemctl stop myapp.service --timeout=300 # May block for 5 minutesThe correct approach: Set a reasonable timeout, or handle the migration logic in postinst.
Collaboration between prerm and other scripts
Test your prerm
Simulated uninstall (keep configuration)
bash
# Installation package
sudo dpkg -i myapp_1.0.0.deb
# Uninstall (triggers prerm remove)
sudo dpkg -r myapp
# Check whether the service has stopped
systemctl status myapp # Should display not found or inactiveSimulated upgrade
bash
# Install old version
sudo dpkg -i myapp_0.9.0.deb
# Upgrade (triggers prerm upgrade)
sudo dpkg -i myapp_1.0.0.debSimulate deconfigure (complex dependency scenario)
bash
# Create two interdependent packages, myapp and mylib
# Triggered when mylib needs to be upgraded but myapp is incompatible
# View the deconfigure log
sudo tail -f /var/log/dpkg.log | grep deconfigureView the prerm execution log
bash
# dpkg detailed log
sudo grep prerm /var/log/dpkg.log
# or use
sudo dpkg --auditremove vs purge vs deconfigure quick reference table
| scene | Trigger command | what prerm does | What postrm does |
|---|---|---|---|
| Uninstall and keep configuration | dpkg -r | Stop service | (Do not run) |
| Completely remove | dpkg -P | Stop service | Delete configuration, logs, and users |
| Upgrade | dpkg -i new | Stop the old version | New version postinst startup |
| Dependency conflict | Automatic trigger | Stop Service (Temporary) | Restore during reconfiguration |
Security checklist: prerm script checklist
Before releasing your Debian package, check against the following checklist prerm:
removeThe scenario only stops services and does not delete any files.upgradeThe scenario only stops the service, not disables it.deconfigureThe scenario only stops services and does not perform destructive operations.failed-upgradeThe scenario is empty or only performs harmless recovery.Use
deb-systemd-invokerather than directlysystemctlAll commands have error handling (
|| trueor conditional judgment)The script uses
exit 0endingDoes not depend on other packages that are not installed.
At
removeRetain all user data in the scene
Summary
| Key points | Explanation |
|---|---|
prerm Run before file deletion | Responsible for "stop" rather than "delete" |
| Four triggering scenarios | remove, upgrade, deconfigure, failed-upgrade |
remove vs purge | prerm only handles remove; data cleanup is in postrm |
deconfigure most complex | Only stop the service, do not perform destructive operations. |
Use deb-systemd-invoke | Do not use systemctl directly |
| Data protection first principle | Never delete user data in prerm |
Next step
In the next chapter, we will explore postrm (post-removal script)—especially purge and remove the boundaries, and how to avoid the fatal problem of the system being unable to reinstall software packages due to script errors.
Next post preview:Chapter 3: The Cleanup Logic of the postrm Script and the purge Trap
