dpkg Does Not Resolve the Graph
In one line
apt is a tool that decides what to install, and dpkg is a tool that installs what has been decided. Once you know this division of labor, you immediately understand why dpkg -i stops with a dependency error.
Why this exists
If you download one .deb file and install it with dpkg -i, you get a message like this.
dpkg: dependency problems prevent configuration of labhub-extra:
labhub-extra depends on labhub-tool (>= 1.2.0); however:
Package labhub-tool is not installed.
dpkg does not know the repository. It does not even know where to fetch what from. It merely unpacks the file it is given, and if the dependencies are not satisfied, leaves it in a "not configured" state. That is why apt-get -f install (fix broken) exists as its partner. It means "apt, look at the repository and finish resolving the unresolved state dpkg left behind."
How it works
A .deb file is actually an ar archive. It holds three pieces.
| Piece | Contents |
|---|---|
debian-binary |
Format version (usually 2.0) |
control.tar.* |
The control file and maintainer scripts (preinst/postinst/prerm/postrm), conffiles, md5sums |
data.tar.* |
The files that are actually unpacked onto the filesystem |
Installation has two steps, unpack → configure. unpack extracts the data, and configure runs postinst to do finishing work such as registering the service. The first two characters of the dpkg -l output show this state.
| Mark | Meaning |
|---|---|
ii |
Install requested + install complete (normal) |
iU |
Install requested + only unpacked (configure failed) |
rc |
Removal requested + only configuration files remain |
pn |
Not installed (purged) |
It is common to overlook the rc state. The answer to "I removed it, so why is the configuration still there?" is here.
dpkg's query commands go in three directions.
dpkg -l # 무엇이 설치돼 있나
dpkg -L coreutils # 이 패키지가 어떤 파일을 깔았나
dpkg -S /usr/bin/ls # 이 파일은 누가 깔았나
dpkg -s coreutils # 이 패키지의 메타데이터는 무엇인가
dpkg-query -W -f='${Package} ${Version}\n'
The third (-S) is the one used most often in practice. When you meet a binary of unknown origin on an unfamiliar server, it separates in one second whether a package installed it or a person placed it by hand. If dpkg -S finds nothing, that file is outside package management, and such files tend not to disappear on upgrades and not to be captured in backups.
What it looks like in the field
A configuration file conflict. During an upgrade, a Configuration file '/etc/foo.conf' ... What would you like to do? prompt appears. dpkg remembers the md5 of files registered in conffiles, so it can tell whether a person edited them. If you carelessly choose "package maintainer's version" at this prompt, the tuning you put in by hand disappears entirely. In automation scripts you have to state the policy explicitly with -o Dpkg::Options::="--force-confold".
Configuration files are treated specially
The files listed in conffiles inside a .deb follow different rules from the rest. If you do not
know these rules, you meet situations where the configuration vanished after an update or, conversely, the new configuration never came in,
and both have the same cause.
When it updates, dpkg compares three things: the content the package originally put in, the content on disk now, and the content the new package wants to put in.
- If we did not edit it, it quietly replaces it with the new one.
- If we edited it and it is identical to the new one, nothing happens.
- If we edited it and it also differs from the new one, it asks. If it is not interactive, following the default behavior
it keeps ours and places the new file next to it as
.dpkg-dist.
The third case is where the problem lies. In an automated update nobody sees that question, so
the service runs with the configuration entries the new version needs missing from our file.
It quietly runs on defaults and later shows up as strange symptoms. That is why you need a procedure that, after an update,
scans for whether .dpkg-dist, .dpkg-new, or .ucf-dist files have appeared.
The relationship between the rc state and configuration files is explained here too. As we saw earlier, the reason configuration remains even after you delete a package is that remove does not touch conffiles,
and purge deletes those as well. So if you reinstall the same package, the old configuration comes back to life,
and "I reinstalled cleanly but get the same problem" comes from here.
Finally, if you plan to manage a configuration file outside the package, it is better to put it in a separate file that is not in
conffiles at all. This is why most packages provide a directory such as conf.d/. The files in it are not owned by the package, so an update does not touch
them, and the three-way comparison itself never happens.
What you will do in the next lab
You query the system with dpkg -L/-S/-s, and build a .deb yourself from a fixture directory and even install it. Once you have built a package, you know for certain what is inside it.