While commit 83c1e8ff5f added support for interactive polkit
authentication in `updatectl`, some users might want to disable that for
some use cases; so add the standard `--no-ask-password` argument.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Helps: https://github.com/systemd/systemd/issues/37412
I am really not a fan of full code lines passed to macros as parameters.
Let's get rid of the 3rd parameter of FOREACH_OPTION() hence:
1. Let's return errors just as a regular value (though a negative one),
that can be handled via a OPTION_ERROR case statement for the switch.
This normalizes handling of the error, just like any other event
returned by the option parser.
2. In order to avoid exploding the amount of boilerplate in each use
(that just propagates the error on OPTION_ERROR), let's then
introduce an explicit FOREACH_OPTION_OR_RETURN(), that returns from
the calling function on its own (and makes that clear in the name).
Together this cleans up, normalizes the logic and shortens the code.
It was requested to make the 'c', 'opt', and 'arg' params the same, i.e.
defined through the FOREACH_OPTION macro. But we can't do that easily,
because 'c' was defined in the for loop definition, and we can only
define variables of the same type in that way. Also, in some cases we
need only 'c', in other cases with need 'c' and 'arg, in some cases 'c'
and 'opt', and in other cases all three. We'd need to either
conditionalize or mark those variables with _unused_ to deal with
compiler warnings. But a different approach works quite nicely: add
state.opt and state.arg to show the current option and it's argument.
(The short names are picked on purpose to reduce verbosity since those
are used a lot.)
If an update is partially downloaded and the user tries to update again,
`updatectl` can’t currently do anything (it doesn’t yet support resuming
downloads). At the moment, though, it’ll return success as if the system
was up to date, even though it isn’t up to date.
Instead, print a more helpful error message telling the user to try
vacuuming the partial version and trying again.
I decided not to make it automatically vacuum the partial version, as
that seems like a way to get into a nasty retry loop if, for example,
the checksum provided by the server doesn’t match that of the downloaded
file (which is one way to trigger this code path).
Add an integration test which simulates this failure by corrupting the
`SHA256SUMS` file, trying to download an update, and then working
through the recovery steps.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Fixes: https://github.com/systemd/systemd/issues/41502
When running `updatectl update` since f0b2ea63, Install() was called
with the version resolved by Acquire() rather than the originally
requested (empty) version, causing the stricter update-to-version polkit
action to be used instead of the update polkit action.
We often have a pattern where the same verb function is used for
multiple actions. This leads to an antipattern where we figure out what
action needs to be taken from argv[0] multiple times: often once in
parse_argv() to figure out what options are allowed, then once again
implicitly in dispatch_verb(), and then again in the action verb itself.
Let's allow passing a parameter into the verb to simplify this.
This matches a pattern we have in conf-parser.h, where we have both
void *userdata (more global) and void *data (per-config item). Here,
I opted for uintptr_t userdata. It seems that most of the time we'll
want to just pass an enum value. This works OK with no casts. I also
tried a void* and union. In both cases, much more boilerplate is needed:
either a cast or a macro to help avoid compiler warnings. uintptr_t
seems generic enough to cover foreseeable usecases with no fuss.
This is a noop refactoring. See next commit for an example.
Rather than calling `Update()`. This should allow us to eventually drop
`Update()`.
This should just be an internal change, and should not result in any
user-visible changes to the behaviour of `updatectl update`.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Helps: https://github.com/systemd/systemd/issues/34814
Let's move some logic from _DEFINE_MAIN_FUNCTION() and other places
in main-func.h into functions that we implement in main-func.c to
allow moving some included headers from the header to the .c file.
Admittedly, some of our glyphs _are_ special, e.g. "O=" for SPECIAL_GLYPH_TOUCH ;)
But we don't need this in the name. The very long names make some invocations
very wordy, e.g. special_glyph(SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY).
Also, I want to add GLYPH_SPACE, which is not special at all.
If there are no updates available, `updatectl check` would previously
just print an empty table. We should instead just tell the user that
there are no updates available.
The progress_bar functions do their own buffering: they reconfigure
stderr, then print, then flush and disable buffering on their own. In
situations where multiple progress bars are being drawn at a time (for
example, in updatectl), it's even more efficient to hoist the buffering
and flushing to the call site, and avoid drawing each progress bar
individually.
To that end, new _unbuffered variants of the progress_bar functions. And
we use them in updatectl.
This applies a couple of aesthetic changes to the way updatectl renders
progress information
1. We invert from "ICON TARGET MESSAGE" to "TARGET: ICON MESSAGE" to
better fit in with the systemd progress bars, which look like
"TARGET [==========---------] XX%". The original version of the
sysupdated PR implemented its own progress bars that were oriented
differently: "[==========---------] TARGET XX%". When we swapped
the progress bar we didn't swap the status messages
2. When a target finishes updating, instead of leaving a 100% progress
bar on screen for potentially extended periods of time (which implies
to the user that the update isn't actually done...), we show a status
message saying the target is done updating.
3. Fixed a minor bug where an extra newline would be printed after the
total progress bar. At the top of the rendering function, we scroll
the terminal's scroll-back just enough to fit a line for each target,
and one for the total. This means that we should not print an
additional line after the total, or else it'll scroll the terminal's
buffer by an additional character. This bug was introduced at some
point during review
4. Clears the Total progress bar before quitting. By the time we're
quitting, that progress bar will be showing no useful status for the
user. Also, the fix in point 3 will cause the shell's prompt to
appear on the same line as the Total progress bar, partially
overwriting it and leaving the shell in a glitchy state.
When enumerating what versions exist for a given target, sysupdate would
completely throw out any version that's incomplete (where some of the
transfers in the target have that version installed or available, and
other transfers do not).
If we're trying to find what versions we can offer for download, this is
great behavior. If the server side is advertising a partial update to
download, we shouldn't present it to the user.
On the other hand, if we're enumerating what versions we have currently
installed, this is a bad behavior. It makes sysupdate fragile. For
example, if a sysext introduces a new .conf file into
/usr/lib/sysupdate.d, suddenly the currently-installed OS stops being a
version that we've enumerated. Since it's not enumerated, it's not
protected, and so sysupdate will wipe the booted OS.
So if we're looking for installed versions, we now loosen the
restrictions and enumerate incomplete installations.
Partial fix for https://github.com/systemd/systemd/issues/33339