Home / Alt manpages / dpkg-realpath(1)

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

Resolve Package Paths Safely with dpkg-realpath

You will finish with a repeatable way to canonicalise package paths against a staging or alternate installation root. 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. The checks are read-only, so they do not require elevated privileges.

The awkward detail is also the useful one: the root directory is used while resolving the pathname, but it is not 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 run and record its version before relying on version-specific behaviour:

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

The command was introduced in dpkg 1.20.1. The --zero option was added in dpkg 1.20.6. Older systems may not have the command or that option, so check rather than assuming that a script can use them everywhere.

Checkpoint: if command -v finds nothing, install or select the dpkg package supplied by your distribution. Do not replace the command with an unverified local script in a maintainer workflow.

2. Resolve a normal system path

Give the command one pathname. It prints an absolute canonical pathname followed by a newline:

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

Canonicalisation removes the .. component and follows the symbolic link from /usr/bin/sh to the shell installed here. Your result can differ if that link points to another shell. The command does not change the link or the target.

A pathname is required. A missing pathname is not a useful way to ask for the current directory, so keep the input explicit in scripts. Use --help to inspect the accepted options without changing anything.

3. Resolve inside a staging root

Create or choose a root directory that contains the filesystem you are examining. The following example assumes an image is mounted at /srv/image and wants the path /usr/bin/sh inside that image:

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

The output is relative to /srv/image, so it is /usr/bin/dash, not /srv/image/usr/bin/dash. This is the form dpkg helpers can pass to other operations that already understand the installation root.

For a harmless local test, make a small tree under /tmp and add 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. That result is a useful sanity check: the tool is resolving the path in the image, not merely normalising characters in the caller's filesystem.

Warning: do not prepend the root to the pathname as well. This is wrong:

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

It asks the tool to resolve a path named /srv/image/usr/bin/sh inside the image. The root would effectively be duplicated in the lookup. Give it the path as seen from the image root.

4. Select the root with DPKG_ROOT

Set DPKG_ROOT when the root is part of the surrounding dpkg-aware environment and you do not want to repeat the option:

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

The environment variable is used only when neither --root nor --instdir is specified. An explicit option therefore 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

Both --root and --instdir set the same base directory for this command. Use the spelling that matches the surrounding dpkg workflow. If no option or DPKG_ROOT is present, the base is /.

5. Make output safe for pipelines

Normal output ends with a newline. When a pathname may contain a newline, request a NUL terminator and pass 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

The final byte is 00. Do not pipe this form into a tool that expects newline-delimited text, because it will receive no newline. --zero affects only the output terminator; it does not alter path resolution.

6. Diagnose a surprising result

First print the exact root and input your script is using. The most common mistake is passing a host path where an image-relative path is required:

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 that the intended file exists. The installed command can canonicalise a path lexically even when the final object is absent, so use an explicit existence check when 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"

Keep the existence check separate from the command's output. The returned path is root-relative; prefix it with the same trusted root only when inspecting the host-side image. Do not use an untrusted root value in a privileged command without validating where it points.

Done means

  • dpkg-realpath --version identified the installed dpkg release.
  • The input path was written relative to the selected filesystem root, without that root being repeated.
  • --root, --instdir or DPKG_ROOT selected the intended base directory.
  • Scripts use --zero only with consumers that expect NUL-delimited output.
  • Existence was checked separately when a real file or link target was required.