pkg-repair(1)
NAME
pkg-repair - restore an installed package's drifted files from its payload
SYNOPSIS
pkg repair [options] name
DESCRIPTION
pkg-verify(1) tells you a file isn't what the package installed. This puts it back.
Repair runs the same per-file check as verify, and for every subpackage that has drifted, it lays the package's payload down again. The payload is the exact bytes the manifest describes, so afterwards every file matches its manifest again.
name is a bare name, which repairs every installed subpackage of it, or name/subpkg for just one.
A package that verifies clean is left alone:
gzip verifies clean; nothing to repair
What gets rewritten?
The whole payload of each drifted subpackage, not just the files that failed. Every file is checked against its sha256 as it's written, then renamed into place. The clean files come out identical to what was there, so you won't notice, but they are rewritten. Subpackages that verified clean aren't touched at all.
A file that couldn't be read is a different matter. Verify has no verdict on it, so repair has no business overwriting it. It warns, and leaves it:
warning: cannot read /etc/secret/a.conf; not repaired
Where do the bytes come from?
From the repository the package came from, so that has to be reachable, either on local disk or over the network. A payload that pkg-stage-update(1) already fetched is used from the stage, without going back to the repository.
What it isn't for
Repair restores what the manifest says, and nothing else. It doesn't resolve anything, it doesn't upgrade, and it never changes the installed version. It's the answer to "something modified these files". It isn't the answer to "this package is broken", which is pkg-upgrade(1), or a remove and an install.
Racing another transaction
Repair takes the same lock on the root that an install takes, after any confirmation prompt. If another transaction replaced one of the drifted subpackages between the scan and the lock, laying the old payload down would be drift. So it refuses, restores nothing, and asks you to run it again:
error: repair: gzip/bin: changed by another transaction since the scan; nothing restored, re-run
And if a file still fails after it was restored, say on a read-only filesystem, that's an error too. It isn't reported as repaired.
OPTIONS
--rootDIR- The filesystem root the package's files are restored under. Same as
pkg verify --root. Defaults to/. --dry-run- Report which files would be restored, and write nothing.
All global options apply; see pkg(1).
OUTPUT
gzip/bin: restored 2 file(s) /usr/bin/zcat /usr/share/man/man1/gzip.1 repaired 2 file(s)
The count is the files that had drifted, not every file the payload rewrote. Under --dry-run:
gzip/bin: would restore 2 file(s) /usr/bin/zcat /usr/share/man/man1/gzip.1 would repair 2 file(s) (dry run; nothing written)
CONFIRMATION
Repair changes the system. At the default confirm level of destructive it doesn't prompt. At all it does. See pkg.toml(5).
EXAMPLES
The usual sequence
Look, look closer, fix, and look again:
pkg verify gzip --quiet pkg repair gzip --dry-run pkg repair gzip pkg verify gzip --quiet
One subpackage
pkg repair gzip/bin
After an accidental delete
rm /usr/bin/gunzip pkg verify gzip --quiet pkg repair gzip
A mounted image
pkg --state-root /mnt/image/var/lib/pkg \ repair coreutils --root /mnt/image
Everything that drifted
pkg --json list | jq -r '.packages[].name' | sort -u \ | while read -r p; do pkg --json verify "$p" | jq -e '.failed > 0' >/dev/null \ && pkg --yes repair "$p" done
Look before you repair
Repair overwrites. When the drift might be deliberate, look first:
pkg verify openssh --quiet pkg repair openssh --dry-run
A config file you meant to change shows up as drift, and repair will happily put it back. That's what you asked for.
Scripting
pkg --json repair gzip --dry-run | jq '.repaired' pkg --json --yes repair gzip | jq '.repaired[].package'
Watching what it found
pkg -v repair coreutils --dry-run pkg -vvv repair coreutils --dry-run 2>&1 | grep drifted
EXIT STATUS
0 on success, including when there was nothing to do. 1 when the name isn't installed, a payload can't be fetched, another transaction got in between, or a file still fails after it was restored.
SEE ALSO
pkg(1), pkg-verify(1), pkg-query(1), pkg-upgrade(1), pkg-install(1), pkg-stage-update(1), pkg.toml(5), pkg-state(5), pkg-repository-layout(7)