An unattended run takes twenty minutes and said nothing at all while it worked. The notification area now carries a live entry for the duration - which step is running, which package is being unpacked, item count, percentage. It is a job in the sense of org.kde.JobViewServer, the same mechanism Dolphin uses while copying files, rather than a notification, which is what makes it a real bar instead of a line of text. That mechanism needs a process of its own. The desktop ties a job to the D-Bus connection that requested it and withdraws it the moment that connection closes, so gdbus, busctl and dbus-send cannot drive one at all - every invocation is a fresh connection that closes again immediately. A small helper therefore runs inside each graphical session for the length of the update, holding the connection open and taking instructions on stdin. It needs python-gobject; without it there is no bar and nothing else changes. Position within the repository step is read from pacman's own "(120/260) upgrading foo" lines. Its other (n/m) sequences are ignored on purpose: checking keys, package integrity and loading files each count up to the same total, and following them would run the bar to the end three times before the first package was unpacked. The "system updated" notification never arrived, which is what prompted looking at any of this. Tagged notifications were posted with --replace-id naming the start message, and Plasma silently drops a Notify() whose replaces_id points at an expired notification: no bubble, no error, and the id it hands back is the dead one it just ignored. The start bubble times out in seconds and a run lasts minutes, so the result fell into exactly that hole every single time. The previous message is now withdrawn and a fresh one posted. How long a message stays is set per message rather than left to the daemon. Anything reporting that the machine still needs a person - a failed update, a locked package database, packages that had to be held back - waits until it is dismissed. Everything else times out on its own, a successful update included; nothing should have to be clicked away for having gone right. Daemons do keep critical-urgency messages up and the specification asks them to, but that is a should, it says nothing about the normal-urgency messages here that still need somebody to act, and urgency separately governs sound and do-not-disturb. "Restart recommended" is gone, and NotifyReboot with it. The running kernel loses its module tree the moment pacman unpacks the new one, so the notice fired while the run was still building AUR packages and pulling Flatpaks, where it reads as an invitation to restart in the middle of an update. The state is still recorded and cachy-auto-update status still reports it. The option went rather than only its default, because an installed system keeps its own configuration file and would have carried on notifying regardless.
208 lines
8.5 KiB
Scdoc
208 lines
8.5 KiB
Scdoc
cachy-auto-update(1)
|
|
|
|
# NAME
|
|
|
|
cachy-auto-update - unattended background updates for CachyOS
|
|
|
|
# SYNOPSIS
|
|
|
|
*cachy-auto-update* [_command_] [_options_]
|
|
|
|
# DESCRIPTION
|
|
|
|
*cachy-auto-update* keeps a CachyOS machine current without anybody having to
|
|
think about it: repository packages, AUR packages, Flatpaks and AppImages are
|
|
updated in the background, with no password prompt and no terminal.
|
|
|
|
Run without a command it opens a small interactive menu with the two switches
|
|
that matter - automatic updates on/off and notifications on/off - plus the
|
|
current status, and a settings screen covering every remaining option so the
|
|
configuration file never has to be edited by hand. In the settings screen the
|
|
arrow keys select, Space or Right changes a value, and _q_ goes back; every
|
|
change is written out immediately.
|
|
|
|
The actual work is done by a systemd system service. The timer ticks hourly;
|
|
whether a tick does anything is decided by _UpdateInterval_ (daily by default).
|
|
A run that is postponed - low battery, a game running, somebody else using
|
|
pacman - is simply retried at the next tick.
|
|
|
|
# COMMANDS
|
|
|
|
*enable*
|
|
Turn automatic updates on and enable the systemd timer.
|
|
|
|
*disable*
|
|
Turn automatic updates off and stop the timer.
|
|
|
|
*notifications* on|off
|
|
Turn desktop notifications on or off.
|
|
|
|
*status*
|
|
Show the current state plus an evaluation of every condition that can
|
|
postpone a run. This is the first thing to look at when the updater
|
|
appears to be doing nothing.
|
|
|
|
*run* [--force] [--dry-run]
|
|
Update now. *--force* skips the interval, battery and gaming checks;
|
|
*--dry-run* lists what would be updated and changes nothing. The check
|
|
for another running package manager is never skipped.
|
|
|
|
*log* [-n _num_] [-f] [-a]
|
|
Show the log of the last run. *-a* shows the rolling log instead, *-f*
|
|
follows it.
|
|
|
|
*-h*, *--help*
|
|
Show a short help text.
|
|
|
|
*-V*, *--version*
|
|
Show the version.
|
|
|
|
# CONDITIONS
|
|
|
|
Before anything is installed, a run is postponed when:
|
|
|
|
- the battery is below _MinBatteryPercent_ (ignored on mains power, and on
|
|
machines without a battery);
|
|
- _RequireAC_ is set and the machine is not plugged in;
|
|
- a game is running - detected via GameMode, a list of known game processes, or
|
|
an application holding a blocking idle inhibitor;
|
|
- pacman's database is locked, or pacman, yay, paru, pamac or a similar tool is
|
|
running.
|
|
|
|
The last check is what keeps *cachy-auto-update* out of the way of manual
|
|
package management. It cannot work in the other direction: if a manual pacman
|
|
run starts while an update is already in flight, that run will report the usual
|
|
locked-database error.
|
|
|
|
# HOW UPDATES ARE APPLIED
|
|
|
|
Repository packages are updated with *pacman -Syu --noconfirm*, but only after
|
|
*checkupdates*(8) has confirmed there is something to do, so on a quiet day
|
|
pacman's lock is never taken at all.
|
|
|
|
A package that has to replace another one is handled silently. If pacman would
|
|
stop to ask whether a conflicting package may be removed, the transaction is
|
|
retried once with that question answered affirmatively, unless
|
|
_AutoResolveConflicts_ is turned off. Files on disk that collide with a package
|
|
are *not* forced - that stays a human decision. A signature failure triggers one
|
|
keyring refresh and one retry.
|
|
|
|
AUR packages are built and installed as the locked *cachy-auto-update* system
|
|
account, because *makepkg*(8) refuses to run as root. That account has no
|
|
password and no shell, and is allowed - through _/etc/sudoers.d/cachy-auto-update_
|
|
- to invoke *pacman* without one. No user password is ever stored anywhere.
|
|
|
|
A failed AUR build is not reported the first time it happens; only a failure
|
|
that repeats is worth waking somebody up for.
|
|
|
|
Flatpak system installations are updated directly as root, user installations
|
|
inside each user's own account. AppImages are updated through Gear Lever, for
|
|
users with a graphical session, and AppImages whose application is currently
|
|
running are skipped.
|
|
|
|
The machine is never restarted automatically. A kernel update that makes a
|
|
restart necessary is reported by *cachy-auto-update status*, not by a
|
|
notification: the running kernel loses its module tree as soon as pacman
|
|
unpacks the new one, so a bubble would fire while the run is still working
|
|
through AUR packages and Flatpaks, and reads as an invitation to restart in the
|
|
middle of it.
|
|
|
|
# PROGRESS
|
|
|
|
For as long as a run is working, the notification area carries a live progress
|
|
entry: the step being performed, how many items it has got through, an overall
|
|
percentage, and the package currently being unpacked under "Details". This is a
|
|
job in the sense of *org.kde.JobViewServer*, the same mechanism a file manager
|
|
uses while copying, rather than a notification - which is what makes it a bar
|
|
instead of a line of text.
|
|
|
|
The desktop withdraws a job as soon as the D-Bus connection that requested it
|
|
closes, so a helper process runs inside each graphical session for the duration
|
|
of the update and holds that connection open. It requires _python-gobject_.
|
|
Where that is missing, or on a desktop with no job interface, there is no
|
|
progress entry and nothing else is affected.
|
|
|
|
The position within the repository step is read from pacman's own
|
|
"(120/260) upgrading foo" output. Its other (n/m) sequences - checking keys,
|
|
package integrity, loading package files - each count up to the same total and
|
|
are deliberately ignored.
|
|
|
|
# HOW LONG NOTIFICATIONS STAY
|
|
|
|
A message that reports the machine still needing a person - an update that
|
|
failed, a package database left locked, packages that had to be held back -
|
|
stays on screen until it is dismissed. A message like that is only worth
|
|
sending if it is still there when somebody comes back to the machine.
|
|
|
|
Everything else times out by itself, an update that simply worked included.
|
|
Nothing should have to be clicked away for having gone right.
|
|
|
|
This is set per message rather than left to the notification daemon. Daemons do
|
|
keep critical-urgency messages up, and the specification asks them to, but that
|
|
is a recommendation, it does not cover the normal-urgency messages here that
|
|
still need somebody to act, and urgency separately governs sound and whether
|
|
do-not-disturb is overridden.
|
|
|
|
Where nobody is logged in the message is spooled and delivered at the next
|
|
login, with the same distinction preserved.
|
|
|
|
# INTERRUPTED UPDATES
|
|
|
|
Before a transaction starts, a notification says an update is running and asks
|
|
for the machine to be left on. It is withdrawn again when the result arrives,
|
|
so one bubble is used rather than two.
|
|
|
|
While a transaction is running, *cachy-auto-update* holds a
|
|
*systemd-inhibit*(1) lock on _sleep_ and _shutdown_ in blocking mode, so a
|
|
suspend, a lid close or a normal shutdown request cannot cut it short.
|
|
|
|
What a user sees when they try anyway is worth knowing: logind refuses the
|
|
request and falls back to the polkit action
|
|
_org.freedesktop.login1.power-off-ignore-inhibit_, which is _auth_admin_keep_,
|
|
so the desktop presents an administrator password prompt reading "Power off the
|
|
system while an application is inhibiting this". That string is shipped
|
|
untranslated by systemd and does not mention updates, and no KDE dialog
|
|
explains the situation either - only *systemctl*(1) names the inhibitor and its
|
|
reason. Hence the notification.
|
|
|
|
A hard power-off - holding the power button, or losing mains power - is not
|
|
preventable. On the next run a leftover _/var/lib/pacman/db.lck_ is removed if
|
|
it is older than the current boot, since no process able to hold it can still
|
|
exist; the upgrade is then repeated and pacman reinstalls whatever was caught
|
|
half-written. A lock file that is unheld but was created during the current
|
|
boot is reported rather than removed, because there is no way to prove it is
|
|
abandoned.
|
|
|
|
Without that recovery a single power cut would leave a lock that makes every
|
|
subsequent run defer, silently stopping updates for good.
|
|
|
|
On Btrfs with *snapper*(8) and *snap-pac*, each pacman transaction is bracketed
|
|
by a pre and post snapshot, so a broken upgrade remains rollbackable.
|
|
|
|
# FILES
|
|
|
|
_/etc/cachy-auto-update/cachy-auto-update.conf_
|
|
Configuration. See the comments in the file itself for every option.
|
|
|
|
_/etc/sudoers.d/cachy-auto-update_
|
|
Lets the build account call pacman without a password.
|
|
|
|
_/var/log/cachy-auto-update/last-run.log_
|
|
Full output of the most recent run.
|
|
|
|
_/var/log/cachy-auto-update/cachy-auto-update.log_
|
|
Rolling log across runs.
|
|
|
|
_/var/lib/cachy-auto-update/_
|
|
State: timestamps, counters, queued notifications.
|
|
|
|
# SEE ALSO
|
|
|
|
*pacman*(8), *checkupdates*(8), *paru*(8), *yay*(8), *flatpak*(1),
|
|
*systemd.timer*(5)
|
|
|
|
# AUTHOR
|
|
|
|
Felitendo. Source and bug reports:
|
|
https://github.com/Felitendo/cachy-auto-update
|