Files
mesh-catalog/modules/pacman
jschoubben 1de9a903c8 issue 1840/S6: keep the node's packages in installed, read at the keeper's start and at every released lock
The keeper reads pacman's database into installed.<node> and writes it only when it differs from the key,
says each change as package.changed, and keeps the last value when the list is over the bus's cap, marking
the node not current until it fits again; the health names the size. The loop runs over injected states,
events, clock, watch and machine, and leaves hooks (start, after a transaction, state watches, wakes) for the
upgrade parts of ADR 0508.
2026-10-22 14:31:33 +02:00
..

pacman

The package manager as a module (novox/hq to-be 42 Phase 1, ADR 0207, research 027). It holds the node-package-manager seat, which has no verbs yet. Every module that declares a package depends on that seat (ADR 0207).

What it owns

  • The pacman package. A component's own package belongs to the module that holds its seat (ADR 0207).
  • /etc/pacman.conf, whole. A block cannot be added to [options] by appending: anything added at the end of the file lands in the last repository's section. So the module owns the file:
    • The repositories are the union of what the four machines had enabled on 2026-10-04: core, extra and multilib. All four had all three.
    • The options are the distribution's defaults, plus Color, ParallelDownloads = 5, VerbosePkgLists, and DownloadUser = alpm (pacman 7; the alpm user exists on all four).
    • The manifest test runs pacman-conf on the rendered file and checks the repository list and the options as pacman reads them. It skips that check where pacman-conf is absent.
    • The host keeps the machine's previous file once, the first time it writes over it (ADR 0102).
  • Mirrors. The reflector package, /etc/xdg/reflector/reflector.conf written whole (https, Belgium, the Netherlands, Luxembourg, Germany, France, the 20 most recently synced, sorted by rate, saved to /etc/pacman.d/mirrorlist), and reflector.timer running and enabled. The mirror list stays reflector's to write, not the mesh's.
  • Cache cleaning. The pacman-contrib package and paccache.timer running and enabled. Each week it keeps the last three versions of each package.
  • The weekly upgrade (ADR 0477 clause 5, issue 1574). mesh-pacman-weekly-upgrade.timer and its oneshot service, placed whole in /etc/systemd/system. The timer fires every Saturday at 04:00 in the node's local time, the same moment on every node (no random delay), and is Persistent=true: a node that was off or asleep then upgrades at its next start. The service runs /usr/bin/pacman -Syu --noconfirm, the same arguments pacman_upgrade starts (UpgradeArgs in the code; a manifest test holds the two together). No other moment upgrades but a hand pacman_upgrade, and the mesh restarts no machine for an upgrade: a new kernel waits for the next restart.
    • The outcome is the module's health. The timer's resource asks pacman_upgrade_health: unhealthy, naming the exit and the last error: line of the journal, when the last weekly upgrade failed; healthy while it runs, after it passed, and before it ever ran. The controller raises the module's condition for the node from it. A failed service stays failed until the next run, so the condition stands until an upgrade passes; a hand pacman_upgrade does not clear it. A restart of the machine clears the failed state and with it the condition, and the next Saturday runs again. A run that goes on longer than two hours is unhealthy too, naming when it started and the last line of its journal: it is hung and holds pacman's database lock. The service has no start timeout on purpose, because killing pacman in the middle of a transaction is worse; the hung run is said, not killed.

What it improves

  • Mirrors were generated once and never again: in 2022, 2023 and 2024, and on one machine by its hosting provider's installer. The list is now refreshed weekly. The timer's first run is at the next weekly boundary; pacman_mirrors with refresh: true runs it at once.
  • Package caches were never cleaned. One workstation held 48 GB, of which paccache would free 33 GB.
  • Every machine has the same options. Only one had parallel downloads.

What it leaves found

  • /etc/pacman.d/mirrorlist, which reflector rewrites, and the stale mirrorlist.pacnew, .bak, .original and similar copies beside it.
  • /etc/pacman.d/hooks, the keyring, and the AUR helper. Packages from outside the repositories are research 027 question 1.

Tools

tool answers
pacman_search r pacman -Ss: repository, name, version, groups, installed and at which version, description
pacman_info r -Qi, or -Si when not installed, with lists as lists
pacman_installed r every package with version, explicit or dependency, foreign; filters and totals
pacman_owns r which package owns a path, or owned: false
pacman_files r what a package placed, bounded
pacman_updates r checkupdates: what a full upgrade would change, never setting up a partial upgrade
pacman_upgrade a starts pacman -Syu --noconfirm (sudo -n) as a transient unit that outlives the call; answers the unit and the news since the last upgrade; given the unit, how it went
pacman_upgrade_health r whether the weekly upgrade last passed: the timer's health check (see the weekly upgrade above)
pacman_orphans r pacman -Qdt
pacman_remove_orphans a pacman -Rs on named orphans, or all of them, as a unit of its own; a name that is not an orphan is refused
pacman_cache r/a size, interrupted downloads, what paccache would free keeping N; clean: true removes them
pacman_history r /var/log/pacman.log: installs, upgrades, downgrades, reinstalls and removals since a day, and the last full upgrade
pacman_mirrors r/a the list, its generator and age, reflector's options, timer and last run; refresh: true starts reflector
pacman_foreign r pacman -Qm
pacman_news r the distribution's news since the last full upgrade (or a day), over https; no network is reachable: false
pacman_config r pacman-conf: options, repositories, and whether /etc/pacman.conf is the module's

A transaction never runs as the tool's own child. An upgrade takes longer than the 20 s a call may take, and a pacman killed mid-transaction leaves a half-upgraded machine and a lock. So a transaction runs as a transient unit (systemd-run, named mesh-pacman-…), and its log is read from the journal.