Home / Alt manpages / dpkg-realpath(1)

  • dpkg-realpath(1)
  • User command
  • linux

Resolve Package Paths Safely with dpkg-realpath

dpkg-realpath canonicalises a path against a staging or alternate installation root. It sounds dull, until a build script quietly prefixes that root twice and everything breaks. The examples use dpkg-realpath from dpkg 1.22.6ubuntu6.6, installed on this machine, and take about ten minutes. You need a shell and a pathname to inspect; every check here is read-only, so nothing needs elevated privileges.

The awkward detail is also the useful one: the root directory is used while resolving the path, but it is never printed as a prefix. Pass /etc/example, not /srv/image/etc/example, when /srv/image is the root of the image.

1. Check the installed command

Confirm which executable will actually run, and record its version before you rely on anything version-specific:

$ command -v dpkg-realpath
/usr/bin/dpkg-realpath
$ dpkg-realpath --version
Debian dpkg-realpath version 1.22.6.

The command arrived in dpkg 1.20.1, and --zero followed in dpkg 1.20.6. Older systems may have neither, so check rather than assume a script can use them everywhere it runs.

Checkpoint

If command -v finds nothing, install or select the dpkg package your distribution ships. Do not swap in an unverified local script inside a maintainer workflow.

2. Resolve a normal system path

Give the command one pathname and it prints an absolute canonical pathname, followed by a newline:

$ dpkg-realpath /usr/bin/../bin/sh
/usr/bin/dash

Canonicalisation drops the .. component and follows the symbolic link from /usr/bin/sh to whichever shell is installed here. Your result can differ if that link points somewhere else. The command never changes the link or its target, it only reports.

A pathname is required; a missing one is not a sanctioned way to ask for the current directory, so keep the input explicit in any script. --help lists the accepted options without changing anything.

3. Resolve inside a staging root

Create or choose a root directory holding the filesystem you are examining. Here an image is mounted at /srv/image, and the goal is the path /usr/bin/sh inside it:

$ dpkg-realpath --root /srv/image /usr/bin/sh
/usr/bin/dash

The output is relative to /srv/image, so it reads /usr/bin/dash, not /srv/image/usr/bin/dash. That is the exact form other dpkg helpers expect when they already understand the installation root.

For a harmless local test, build a small tree under /tmp with a relative symbolic link:

$ mkdir -p /tmp/dpkg-image/etc /tmp/dpkg-image/var/lib
$ printf '%s\n' data > /tmp/dpkg-image/etc/target
$ ln -s ../etc/target /tmp/dpkg-image/var/lib/link
$ dpkg-realpath --root /tmp/dpkg-image /var/lib/link
/var/etc/target

The link target is relative to /var/lib, so ../etc/target resolves to /var/etc/target. A useful sanity check: the tool is resolving the path inside the image, not simply tidying up characters against the caller's own filesystem.

Warning

Do not prepend the root to the pathname as well. This is the wrong move:

$ dpkg-realpath --root /srv/image /srv/image/usr/bin/sh
/srv/image/usr/bin/sh

That asks the tool to resolve a path literally named /srv/image/usr/bin/sh inside the image, effectively duplicating the root in the lookup. Give it the path exactly as seen from the image root.

4. Select the root with DPKG_ROOT

Set DPKG_ROOT when the root belongs to the surrounding dpkg-aware environment and you would rather not repeat the option every time:

$ DPKG_ROOT=/srv/image dpkg-realpath /usr/bin/sh
/usr/bin/dash

The environment variable is only consulted when neither --root nor --instdir is given, so an explicit option always wins, which makes a command-line override easy to audit:

$ DPKG_ROOT=/wrong-image dpkg-realpath --root /srv/image /usr/bin/sh
/usr/bin/dash

--root and --instdir set the same base directory for this command; pick the spelling that matches the surrounding dpkg workflow. With neither option nor DPKG_ROOT present, the base is /.

5. Make the output safe for pipelines

Normal output ends with a newline. When a pathname might contain one, ask for a NUL terminator and hand the result to a consumer that understands NUL-delimited records:

$ dpkg-realpath --zero --root /srv/image /usr/bin/sh | od -An -t x1
 2f 75 73 72 2f 62 69 6e 2f 64 61 73 68 00

That final byte is 00. Do not pipe this form into a tool expecting newline-delimited text, because it gets no newline at all. --zero only changes the output terminator; it never touches how the path resolves.

6. Diagnose a surprising result

Print the exact root and input your script is using first. The most common mistake is handing it a host path where the tool wants an image-relative one:

root=/srv/image
path=/usr/bin/sh
printf 'root=%s path=%s\n' "$root" "$path"
dpkg-realpath --root "$root" "$path"
status=$?
printf 'status=%s\n' "$status"

A successful status is not proof the file exists: the command can canonicalise a path lexically even when the target is absent, so add an explicit existence check whenever that matters:

resolved=$(dpkg-realpath --root "$root" "$path") || exit $?
test -e "$root$resolved" || {
    printf 'not present in root: %s\n' "$root$resolved" >&2
    exit 1
}
printf '%s\n' "$resolved"

Security boundary

Keep the existence check separate from the command's output. The returned path is root-relative; only prefix it with the same trusted root when inspecting the host side of that image, and never feed an untrusted root value into a privileged command without validating where it actually points.

Done means

  • Version confirmed. dpkg-realpath --version identified the installed dpkg release.
  • Path written relative to the root, once. Not repeated inside the pathname itself.
  • Root selected on purpose. Via --root, --instdir or DPKG_ROOT, deliberately.
  • --zero only reaches consumers built for it. NUL-delimited output, NUL-aware reader.
  • Existence checked separately, whenever a real file or link target actually mattered.