The Ur Project

Documenting the craft of stacking things so they remain stacked. For a very long time.

pkg-triggers(1)

NAME

pkg-triggers - run or list the system trigger ruleset

SYNOPSIS

pkg triggers list

pkg triggers run [--changed PATH]...

DESCRIPTION

Install a library and the linker cache is stale. Install a kernel module and modules.dep is stale. Same for the icon cache, the mime database, the man database, the font cache, systemd presets. These are derived files: each one summarizes a pile of other files, and has to be rebuilt when they change.

Triggers are the rules that do that rebuilding. Every rule has watch globs and a command. A package transaction fires the rules whose globs match the paths it touched, so normally you never think about them. This command is the manual way into the same ruleset, for when you changed files yourself or something needs a kick.

Why do failures always warn?

Triggers run after a transaction has already committed. A failing trigger can't roll anything back. So a failure always shows up as a warning, even without -v. An operator who never finds out that a cache regeneration failed is worse off than one who sees the warning.

Why don't skips warn?

A skipped rule isn't a failure, and gets no warning. The ruleset is system-wide, but no installation carries every tool it names. Warning about a missing dconf on a minimal image would bury the real failures. Skips show up in the counts, and from -v up.

COMMANDS

list

Prints the ruleset: each rule's name, its watch globs, and the command it runs.

ldconfig watch: /usr/lib/lib.so* run: /usr/sbin/ldconfig depmod watch: /usr/lib/modules/* run: /usr/sbin/depmod -a systemd-sysusers watch: /usr/lib/sysusers.d/* run: /usr/bin/systemd-sysusers

run

Runs rules now, against the live system rooted at /. It needs root, and an unprivileged caller is refused before any rule runs.

With --changed, only the rules whose watch globs match those paths run, exactly as a package transaction touching them would.

With no --changed, the whole ruleset runs, and the set of changed paths it's handed is every path owned by an installed package. As if everything had just been installed. That matters: several rules take the changed paths as their arguments, to name a theme, a module or a unit. Given no paths, they'd resolve to zero arguments and quietly do nothing.

A system with no state database yet -- a rescue shell, a half-built image -- gets an empty changed set instead of an error. A state database that can't be read is treated the same way, with a warning. Either way, the rules that take no paths, which is all such a system can run, still run.

OPTIONS

--changed PATH
Only run rules whose watch globs match this path. Can be repeated.

OUTPUT

Quiet by default, except for failures. Each failure gets a warning and the last three lines of its stderr, and a summary line follows:

warning: trigger mandb failed: exit 1 mandb: can't write to /var/cache/man: Read-only file system Triggers: 11 ran, 1 failed, 3 skipped

At -v, a line per rule with its verdict and duration. At -vv, also the command that ran. At -vvv, also each rule's captured stdout and stderr.

JSON

{ "ok": true, "kind": "triggers-run", "ran": 11, "failed": 0, "skipped": 3, "results": [ { "rule": "ldconfig", "status": "ok", "ok": true, "ms": 412 } ] }

triggers list emits kind: triggers-list, with a rules array of {name, watch, command}.

EXAMPLES

What rules exist

pkg triggers list pkg --json triggers list | jq -r '.rules[].name'

Regenerate everything

pkg triggers run

The blunt instrument. Useful after dropping files in by hand, after restoring from a backup, or on the first boot of an image whose prebaked caches are stale.

Regenerate only what one change affects

pkg triggers run --changed /usr/lib64/libfoo.so.1 pkg triggers run --changed /usr/share/applications/foo.desktop

Several paths at once

pkg triggers run \ --changed /usr/lib64/libfoo.so.1 \ --changed /usr/lib/modules/6.12.4/extra/foo.ko

Which rules a path fires

pkg -v triggers run --changed /usr/share/icons/hicolor/index.theme

There's no dry run for this. It really runs the rules it lists.

Seeing what each rule actually ran

pkg -vv triggers run 2>&1 | grep '\$'

Seeing a failing rule's output

pkg -vvv triggers run --changed /usr/share/man/man1/foo.1

After a manual library install

cp libfoo.so.1 /usr/lib64/ pkg triggers run --changed /usr/lib64/libfoo.so.1

Checking that a system's caches are consistent

pkg --json triggers run \ | jq -r '.results[] | select(.ok | not) | .rule'

In a script

if ! pkg --json triggers run > /tmp/triggers.json; then jq -r '.results[] | select(.ok | not) | .rule' /tmp/triggers.json exit 1 fi

Triggers fired by an ordinary transaction

You don't need to run anything separately. Transactions fire their own:

pkg -v install fontconfig

The triggers lines at the end of that run are the same reporting.

EXIT STATUS

0 when every rule that ran succeeded. 1 when any of them failed, or when run was refused for want of root. Skipped rules don't affect the exit status.

SEE ALSO

pkg(1), pkg-install(1), pkg-upgrade(1), pkg-compose(1), ldconfig(8), depmod(8)

docs/design/triggers.md, docs/components/triggers-core.md, docs/components/triggers-runner.md