13.3 Maintainer Scripts and Conffiles

Key Takeaways

  • Packages can ship four maintainer scripts — preinst, postinst, prerm, postrm — executed by dpkg at specific points in the install, upgrade, and removal lifecycle
  • On a fresh install the order is preinst, unpack, postinst configure; on removal the order is prerm remove, delete files, postrm remove, and purge additionally runs postrm purge
  • Maintainer scripts receive arguments like install, configure, upgrade, remove, purge, and abort-* so a single script can handle every code path
  • Conffiles are dpkg-tracked configuration files that survive dpkg -r but are deleted by dpkg -P; when you have modified one, upgrades trigger the conffile prompt
  • --force-confold keeps your version and --force-confnew installs the maintainer's version without prompting; ucf manages config files that are not dpkg conffiles
Last updated: July 2026

The Four Maintainer Scripts

A Debian package is not just files — it can also carry maintainer scripts, shell scripts stored in the control.tar member of the .deb that dpkg executes as root at defined lifecycle points. There are exactly four:

  • preinst — runs before the package's files are unpacked. Used to stop services, check for conflicting state, or back up data the upgrade will touch.
  • postinst — runs after unpacking, to finish configuration: create users, set permissions, run update-alternatives, enable systemd units, and generate initial config.
  • prerm — runs before the package's files are deleted, typically to stop the daemon cleanly.
  • postrm — runs after deletion, to clean up leftovers; on a purge dpkg first deletes the conffiles itself and then calls postrm purge so the script can remove any remaining state the package created.

Each script receives arguments describing what is happening, so one script handles every code path with a case "$1" in ... esac block. The common arguments are install, upgrade (with the old version as $2), configure (with the previously configured version as $2), remove, purge, failed-upgrade, and the error-recovery forms abort-install, abort-upgrade, and abort-remove. When a script exits non-zero, dpkg aborts the operation and runs the corresponding rollback script — for example, if a preinst upgrade fails, dpkg runs postrm abort-upgrade to unwind. This argument-and-rollback convention is heavily tested because it explains why packages can fail halfway and still leave the system consistent.

Lifecycle Order: Install, Upgrade, Remove, Purge

The exact sequencing is the most memorization-heavy part of this topic, so lay it out as a table:

OperationScript sequence
Fresh installpreinst install → unpack files → postinst configure
Upgrade 1.0 → 2.0old prerm upgrade 2.0 → new preinst upgrade 1.0 → unpack new files → old postrm upgrade 2.0 → new postinst configure 1.0
Removeprerm remove → delete package files (conffiles stay) → postrm remove
Purgeeverything from Remove, then conffiles and .dpkg-* backups deleted by dpkg → postrm purge

Two details trip people up. First, during an upgrade the old package's prerm and postrm run, not the new one's — the new package only contributes its preinst and postinst, because the old scripts are the ones that know how the old version must be shut down. Second, postinst configure is the step skipped when a package is left in the iU (unpacked, unconfigured) state — which is why dpkg --configure -a, covered in Section 13.1, repairs it by simply running the pending postinst scripts.

Conffiles: Configuration Files dpkg Protects

A conffile is a configuration file — typically under /etc — that the package declares in its conffiles control file. dpkg records each conffile's original MD5 checksum at install time (visible in dpkg -s package output) and treats these files differently from ordinary package files:

  • dpkg -r package removes the package but keeps conffiles, producing the rc status from Section 13.1.
  • dpkg -P package (purge) deletes conffiles too: dpkg removes them itself and then runs postrm purge.

The rationale: conffiles contain your edits, so removal should not destroy your work, while purge is an explicit "leave nothing behind" decision.

The Conffile Prompt on Upgrade

Trouble arrives when both you and the package maintainer have changed a conffile since the last install. On upgrade, dpkg detects that the on-disk file's checksum differs from the original and stops to ask:

Configuration file '/etc/ssh/sshd_config'
 ==> Modified (by you or by a script) since installation.
 ==> Package distributor has shipped an updated version.
   What would you like to do about it ?  Your options are:
    Y or I  : install the package maintainer's version
    N or O  : keep your currently-installed version
      D     : show the differences between the versions
      Z     : start a shell to examine the situation
 The default action is to keep your current version.
*** sshd_config (Y/I/N/O/D/Z) [default=N] ?

Read this prompt precisely for the exam: the default (Enter, N, or O) keeps your version; Y or I installs the maintainer's version (your file is preserved with a .dpkg-old suffix); choosing to keep yours leaves the new version on disk as .dpkg-dist for comparison. If dpkg finds no local modifications, it silently replaces the file with the new one.

Non-Interactive Control: --force-confold and --force-confnew

Interactive prompts break automation, so dpkg offers force options you will see in unattended Kali upgrade scripts:

$ sudo apt -o Dpkg::Options::="--force-confold" -o Dpkg::Options::="--force-confdef" dist-upgrade
  • --force-confold — always keep the installed version, never prompt.
  • --force-confnew — always install the maintainer's version, never prompt.
  • --force-confdef — let dpkg choose the default action without prompting when one exists; if there is no default it still asks, unless --force-confold or --force-confnew is also given, in which case that option decides (which is why the two are normally paired).
  • --force-confmiss — reinstall a conffile the administrator deleted.

ucf: Config Files Outside dpkg's Tracking

Some packages cannot ship their config as a conffile — for example when the file is generated at install time from a template plus debconf answers, so no fixed checksum exists to declare. Those packages use ucf (Update Configuration File), a helper that keeps its own checksum registry in /var/lib/ucf/hashfile and presents a similar three-way keep/replace prompt for files dpkg itself does not track. The exam distinction is sharp: conffiles are declared in the package and tracked by dpkg; ucf-managed files are generated post-installation and tracked by ucf. This is also the final answer to "why do files under /etc survive a remove?" — dpkg deliberately never touches user-modified configuration until you say purge, and even generated configs get a managed second chance through ucf rather than blind deletion.

What Purge Does Not Remove

A purge is thorough but not total, and the boundary is exam-worthy. postrm purge deletes the package's conffiles and whatever state the maintainer scripted away, but dpkg still will not touch:

  • Runtime data — databases in /var/lib/<package>/, logs in /var/log/, spool files.
  • User accounts and groups created by postinst (a leftover postgres system user is normal after purging PostgreSQL).
  • Files you created inside package-owned directories.

Also keep the file-suffix vocabulary straight, because questions present it as output you must interpret: .dpkg-old is your modified conffile, saved when you accepted the maintainer's version; .dpkg-dist is the maintainer's new version, saved when you kept yours; .dpkg-new is an incoming file temporarily present during the unpack phase. Finally, remember that ucf has its own cleanup path: purging a package whose config is ucf-managed removes the file from ucf's registry, and you can force the question again manually with sudo ucf --purge /etc/somefile.conf followed by reinstalling — a detail that separates ucf-managed files from true conffiles one last time.

Test Your Knowledge

A package is being upgraded from version 1.0 to 2.0. Which maintainer script does dpkg invoke first, before anything else in the upgrade, and who provides it?

A
B
C
D
Test Your Knowledge

You are scripting an unattended Kali dist-upgrade and want every modified conffile to keep the administrator's locally edited version without any prompts. Which dpkg option achieves exactly that?

A
B
C
D