skip to content

Describe what is physically inside a .deb file and inside an .rpm file: where does each format keep its metadata, its file payload, and its maintainer scripts?

level: middleimportance: should knowfreq 45%

answer

  1. ar archive versus tagged binary header
  2. three members: version, control, data
  3. scripts travel with metadata, not with files
  4. payload is cpio on the RPM side
  5. file list is readable before installing

basics

~20 s

A .deb is an ar archive of three members: debian-binary, a control archive holding metadata and maintainer scripts, and a data archive holding the files. An .rpm is a tagged binary header — metadata, file list and scriptlets — followed by a compressed cpio payload.

solid answer

~50 s

The two formats solve the same problem with different containers. A `.deb` is a plain `ar` archive with three members in a fixed order: `debian-binary` (the format version), `control.tar.*` and `data.tar.*`. The control archive holds the `control` file with the package name, version, architecture and its `Depends`/`Conflicts`/`Provides` relationships, plus `md5sums`, a `conffiles` list, and the maintainer scripts `preinst`, `postinst`, `prerm` and `postrm`. The data archive is the payload: the files exactly as they will land on the filesystem. An `.rpm` is not an archive of archives — it is a binary header of tagged key/value entries followed by a compressed `cpio` payload. That header carries everything: name and version, `Requires`/`Provides`/`Obsoletes`, the complete file list with modes and digests, and the scriptlets `%pre`, `%post`, `%preun` and `%postun` stored as header tags rather than as files. A separate signature header precedes it. Because metadata is separate from payload in both, a client can read a package's dependencies and file list without unpacking it.

code

bash · 9 lines
bash
# A .deb is an ar archive with exactly three members
ar t ./myapp_1.2.3_amd64.deb

# Extract just the metadata side, including maintainer scripts
mkdir -p /tmp/ctl && dpkg-deb --control ./myapp_1.2.3_amd64.deb /tmp/ctl
ls /tmp/ctl

# Read the payload file list without installing
dpkg-deb --contents ./myapp_1.2.3_amd64.deb

go deeper

for a junior

Know that a package is a container with two halves — metadata describing the package and a payload of files — and that you can list both without installing anything.

for a middle

Name the structures: a .deb is an ar archive of debian-binary plus a control archive and a data archive; an .rpm is a tagged header followed by a cpio payload. Say where the maintainer scripts live in each.

for a senior

Show that you understand the consequences: scripts run as root at defined points, config files marked as such survive upgrades, and per-file digests in the metadata let you verify an installed system against what the package shipped.

for a principal

Frame packaging as a supply-chain surface you own — arbitrary root code runs at install time, so build reproducibility, who may publish, and what the metadata asserts about provenance matter more than the container format itself.

## Why the anatomy matters Both formats have to answer the same questions before anything is written to disk: what is this package called, what version is it, what does it need, what will it install, and what code must run around the install. How each format stores those answers explains several behaviours that otherwise look arbitrary. ## The .deb container A Debian binary package is an `ar` archive — the ancient Unix archive format also used for static libraries — with exactly three members, in order: 1. **`debian-binary`** — a tiny text file containing the format version, currently `2.0`. Its presence first lets a tool identify the file cheaply. 2. **`control.tar.*`** — the metadata archive (gzip, xz or zstd compressed). 3. **`data.tar.*`** — the payload archive. Inside the control archive: - **`control`** — an RFC822-style stanza with `Package`, `Version`, `Architecture`, `Maintainer`, `Description`, and the relationship fields (`Depends`, `Pre-Depends`, `Recommends`, `Suggests`, `Conflicts`, `Breaks`, `Replaces`, `Provides`). This is the stanza that gets copied into the repository's index file, which is how a resolver can plan without downloading anything. - **`md5sums`** — digests of the shipped files, used to detect local modification. - **`conffiles`** — the list of paths that are configuration and must therefore be *preserved* rather than overwritten when the package is upgraded. - **maintainer scripts** — `preinst`, `postinst`, `prerm`, `postrm`, and optionally `triggers`. These are ordinary executables (usually shell) run by the installer, as root, at defined points around unpacking and removal. The data archive holds the payload as a normal tar tree rooted at `/`: `./usr/bin/myapp`, `./etc/myapp/config`, and so on, with ownership and modes recorded in the tar headers. ## The .rpm container An RPM file is a single binary structure, not a nest of archives: 1. **Lead** — a fixed 96-byte legacy structure, retained for file-type identification only; modern tools do not rely on it. 2. **Signature header** — digests and the GPG signature over the rest of the file, which is why an individual RPM is independently verifiable. 3. **Header** — the real metadata: a tag/value store keyed by numeric tags. It carries name, version, release, epoch, architecture, the `Requires`/`Provides`/`Conflicts`/`Obsoletes` relationships, the complete file list with paths, sizes, modes, users, groups and per-file digests, and the **scriptlets** (`%pre`, `%post`, `%preun`, `%postun`, plus transaction-scoped `%pretrans`/`%posttrans` and trigger scriptlets) stored as header tags with an associated interpreter. 4. **Payload** — a `cpio` archive, compressed with gzip, xz or zstd depending on the distribution's build settings. A consequence worth naming in an interview: because the file list is *in the header*, RPM can tell you every path a package will install, with its mode and digest, without touching the payload — and it can later verify an installed system against those recorded digests. ## Relationship declarations, not bundled dependencies Neither format embeds the packages it depends on. Both declare names and version ranges and leave satisfaction to the resolver. RPM additionally auto-generates fine-grained dependencies at build time: shared-library sonames like `libc.so.6(GLIBC_2.34)(64bit)`, plus interpreter-level requirements. Debian's equivalent granularity comes from `shlibs`/`symbols` files that turn a linked library into a versioned `Depends` on the package that provides it. ## Maintainer scripts are privileged code On both sides the scripts run as root, before and after the files move. They are why installing a package is a trust decision and not merely a file copy: a package can create system users, generate keys, migrate a database schema, or do anything else root can do. The ordering during an *upgrade* is the part candidates get wrong — the new package's pre-install script runs, files are replaced, then the old package's removal script runs with an argument telling it that it is being upgraded rather than purged, and finally the new post-install script runs. A removal script that does not check that argument can happily undo the upgrade it is part of. ## Configuration files get special treatment Because a `conffile` (Debian) or a file marked `%config(noreplace)` (RPM) may have been edited by the administrator, upgrades do not simply overwrite it. Debian's installer compares digests and, if the file was modified, prompts or leaves the new version beside it as `.dpkg-dist`, keeping your version. RPM either installs the new file and saves yours as `.rpmsave`, or keeps yours and drops the new one as `.rpmnew`, depending on the flag used. Finding stray `.rpmnew` files on an old server is a classic sign that upgrades have been applied without anyone reconciling configuration. ## Source packages Both ecosystems also have a source form. A Debian source package is a set of files — a `.dsc` control file, an upstream tarball, and a Debian-specific tarball of packaging — while RPM ships a single `.src.rpm` containing the spec file and its sources. Building either produces the binary packages; distributions build in clean isolated chroots so the result depends only on declared build dependencies.

  • During an upgrade, which maintainer scripts run and in what order?
    The new package's pre-install script runs first, then the files are replaced, then the *old* package's post-removal script runs — with an argument indicating an upgrade rather than a purge — and finally the new post-install script runs. A removal script that ignores that argument and deletes state unconditionally will damage the very upgrade it is part of.
  • Why do you sometimes find .rpmnew or .dpkg-dist files on a long-lived server?
    Both are the packaging system refusing to clobber a configuration file you edited. RPM writes the packaged version beside yours as `.rpmnew` when the file is marked no-replace; Debian leaves the new version as `.dpkg-dist` when it detects local modification. They accumulate when upgrades are applied and nobody reconciles the differences, so the running config drifts from what the package intended.
  • What is the difference between a binary package and a source package?
    A binary package contains built artifacts for one architecture plus the metadata to install them. A source package contains the upstream source plus the packaging recipe — a spec file for RPM, a `debian/` directory for Debian — and is what gets built, ideally in a clean isolated environment, to produce the binaries. Source packages are what make a distribution rebuildable and auditable.

saying these in an interview costs you the question

  • Saying a .deb is just a renamed zip archive
  • Thinking an .rpm is a self-extracting shell script
  • Believing packages bundle their dependencies' files
  • Claiming maintainer scripts live in the file payload
  • Assuming you must install a package to see its file list

context