Register Debian Configuration Files Safely with ucfr

ucfr registers which package owns a configuration file in the ucf database, so an upgrade never guesses. You will also preview the planned change before applying it, and remove the association during a purge. This guide follows the installed Debian implementation, ucfr from ucf version 3.0043+nmu1.

Allow about ten minutes. You need a shell, the ucf package and root privileges for a real registry change. The examples use a fictional package called example-app; substitute the package that actually owns your file.

Checkpoint: This command changes registry metadata, not the contents of the configuration file. It does not create or edit the configuration file itself.

1. Confirm the command and the file path

Use a fully qualified path. ucfr resolves symbolic links and records the real target, so check where a link leads before registering it:

$ command -v ucfr
/usr/bin/ucfr
$ dpkg-query -W -f='${Package} ${Version}\n' ucf
ucf 3.0043+nmu1
$ readlink -f /etc/example-app.conf
/etc/example-app.conf

The first argument is the package name and the second is the configuration file path. In package maintainer scripts, that normally means:

ucfr example-app /etc/example-app.conf

Run the command as root when you are administering a live installation. A maintainer script normally already runs with the required privilege.

2. Preview the association

Use --no-action before making a change. It prints the action it would take and leaves the registry alone:

# ucfr --no-action --verbose example-app /etc/example-app.conf
ucfr: The Package name is example-app
ucfr: The Configuration file is /etc/example-app.conf
ucfr: The (real) Configuration file is /etc/example-app.conf
ucfr: The State directory is /var/lib/ucf
ucfr: The registry exists
replace_in_registry

The exact diagnostic can differ when the file is a symlink or the registry already contains an entry. The useful checks are that the package, resolved path and state directory are the ones you intended, and that replace_in_registry is shown for a normal association.

If you run a non-preview command as an unprivileged user, this version prints Need to be run as root. and switches itself into no-action mode. Do not mistake that message for a successful registration.

3. Register the file

After reviewing the preview, make the association with elevated privileges:

# ucfr example-app /etc/example-app.conf

There is normally no success message. The registry is /var/lib/ucf/registry, with older copies in files such as registry.0. Verify the entry directly:

# grep -F -- '/etc/example-app.conf' /var/lib/ucf/registry
example-app     /etc/example-app.conf

The spacing is not significant. A matching line confirms the package and resolved path are associated. Registering the same package and file again is idempotent: it is not an error and does not create a second association.

Recovery: If you registered the wrong file, do not edit the registry by hand. Use the purge operation in the next step, then preview and register the intended path.

4. Refuse an ownership conflict by default

If another package already owns the path in the registry, an ordinary registration fails rather than silently taking it. This protects a package's ownership boundary:

# ucfr example-app /etc/shared-example.conf
ucfr: Attempt from package example-app to take /etc/shared-example.conf away from old-package
ucfr: Aborting.

Do not add --force merely to make an installation continue. It deliberately permits a package to hijack the association, and it can also remove another package's association during a purge. Investigate the existing package first:

# grep -F -- '/etc/shared-example.conf' /var/lib/ucf/registry

Only use --force when you have a specific ownership transfer to perform and understand the package lifecycle that will restore or remove the entry.

5. Remove the association on purge

A package that registered a file should forget that association when the package is purged. Preview the removal first:

# ucfr --no-action --purge --verbose example-app /etc/example-app.conf
ucfr: The Package name is example-app
ucfr: The Configuration file is /etc/example-app.conf
ucfr: The (real) Configuration file is /etc/example-app.conf
ucfr: The State directory is /var/lib/ucf
ucfr: The registry exists
purge_from_registry

Apply it with root privileges:

# ucfr --purge example-app /etc/example-app.conf
# grep -F -- '/etc/example-app.conf' /var/lib/ucf/registry

No matching output means the association is gone. Purging an association that is already absent is idempotent. If the path belongs to another package, ucfr refuses unless --force is supplied. Leave the other package's entry alone unless you are deliberately repairing an ownership transfer.

6. Test scripts with a separate state directory

The --state-dir option selects a registry directory instead of /var/lib/ucf. The manual describes it as mainly for testing. Use it to inspect package-maintainer logic without touching the live registry:

# mkdir -p /tmp/ucfr-test-state
# ucfr --state-dir /tmp/ucfr-test-state --no-action example-app /etc/example-app.conf
touch /tmp/ucfr-test-state/registry
replace_in_registry

Keep this directory disposable and do not use it as a substitute for the system registry in a real package installation. The option changes where ucfr reads and writes its records, not which configuration file the package uses.

Done means