diff --git a/src/import/importctl.c b/src/import/importctl.c index 27c26a70e88..85903bb8c69 100644 --- a/src/import/importctl.c +++ b/src/import/importctl.c @@ -45,7 +45,7 @@ static const char* arg_format = NULL; static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF; static ImageClass arg_image_class = _IMAGE_CLASS_INVALID; -#define PROGRESS_PREFIX "Total: " +#define PROGRESS_PREFIX "Total:" static int settle_image_class(void) { diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c index 5b18241f00e..db1285e7f0f 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.c +++ b/src/libsystemd/sd-bus/bus-common-errors.c @@ -153,5 +153,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_REBALANCE_NOT_NEEDED, EALREADY), SD_BUS_ERROR_MAP(BUS_ERROR_HOME_NOT_REFERENCED, EBADR), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_UPDATE_CANDIDATE, EALREADY), + SD_BUS_ERROR_MAP_END }; diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index fb1d4211681..622cf4933db 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -158,4 +158,6 @@ #define BUS_ERROR_REBALANCE_NOT_NEEDED "org.freedesktop.home1.RebalanceNotNeeded" #define BUS_ERROR_HOME_NOT_REFERENCED "org.freedesktop.home1.HomeNotReferenced" +#define BUS_ERROR_NO_UPDATE_CANDIDATE "org.freedesktop.sysupdate1.NoCandidate" + BUS_ERROR_MAP_ELF_USE(bus_common_errors); diff --git a/src/partition/repart.c b/src/partition/repart.c index e14c9a4750b..48b3b430137 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -4553,7 +4553,7 @@ static int progress_bytes(uint64_t n_bytes, void *userdata) { p->copy_blocks_done += n_bytes; - if (asprintf(&s, "%s %s %s %s/%s ", + if (asprintf(&s, "%s %s %s %s/%s", strna(p->copy_blocks_path), special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), strna(p->definition_path), diff --git a/src/shared/pretty-print.c b/src/shared/pretty-print.c index f361c4760a0..cc226e72ea7 100644 --- a/src/shared/pretty-print.c +++ b/src/shared/pretty-print.c @@ -460,21 +460,16 @@ bool shall_tint_background(void) { return cache != 0; } -void draw_progress_bar(const char *prefix, double percentage) { - - /* We are going output a bunch of small strings that shall appear as a single line to STDERR which is - * unbuffered by default. Let's temporarily turn on full buffering, so that this is passed to the tty - * as a single buffer, to make things more efficient. */ - char buffer[LONG_LINE_MAX]; - setvbuf(stderr, buffer, _IOFBF, sizeof(buffer)); - +void draw_progress_bar_unbuffered(const char *prefix, double percentage) { fputc('\r', stderr); - if (prefix) + if (prefix) { fputs(prefix, stderr); + fputc(' ', stderr); + } if (!terminal_is_dumb()) { size_t cols = columns(); - size_t prefix_width = utf8_console_width(prefix); + size_t prefix_width = utf8_console_width(prefix) + 1 /* space */; size_t length = cols > prefix_width + 6 ? cols - prefix_width - 6 : 0; if (length > 5 && percentage >= 0.0 && percentage <= 100.0) { @@ -518,6 +513,33 @@ void draw_progress_bar(const char *prefix, double percentage) { fputs(ANSI_ERASE_TO_END_OF_LINE, stderr); fputc('\r', stderr); + +} + +void clear_progress_bar_unbuffered(const char *prefix) { + fputc('\r', stderr); + + if (terminal_is_dumb()) + fputs(strrepa(" ", + prefix ? utf8_console_width(prefix) + 5 : /* %3.0f%% (4 chars) + space */ + LESS_BY(columns(), 1U)), + stderr); + else + fputs(ANSI_ERASE_TO_END_OF_LINE, stderr); + + fputc('\r', stderr); +} + +void draw_progress_bar(const char *prefix, double percentage) { + + /* We are going output a bunch of small strings that shall appear as a single line to STDERR which is + * unbuffered by default. Let's temporarily turn on full buffering, so that this is passed to the tty + * as a single buffer, to make things more efficient. */ + char buffer[LONG_LINE_MAX]; + setvbuf(stderr, buffer, _IOFBF, sizeof(buffer)); + + draw_progress_bar_unbuffered(prefix, percentage); + fflush(stderr); /* Disable buffering again */ @@ -525,23 +547,12 @@ void draw_progress_bar(const char *prefix, double percentage) { } void clear_progress_bar(const char *prefix) { - char buffer[LONG_LINE_MAX]; setvbuf(stderr, buffer, _IOFBF, sizeof(buffer)); - fputc('\r', stderr); + clear_progress_bar_unbuffered(prefix); - if (terminal_is_dumb()) - fputs(strrepa(" ", - prefix ? utf8_console_width(prefix) + 4 : - LESS_BY(columns(), 1U)), /* 4: %3.0f%% */ - stderr); - else - fputs(ANSI_ERASE_TO_END_OF_LINE, stderr); - - fputc('\r', stderr); fflush(stderr); - /* Disable buffering again */ setvbuf(stderr, NULL, _IONBF, 0); } diff --git a/src/shared/pretty-print.h b/src/shared/pretty-print.h index 2c97c354ef0..d3af149a2ef 100644 --- a/src/shared/pretty-print.h +++ b/src/shared/pretty-print.h @@ -55,3 +55,5 @@ bool shall_tint_background(void); void draw_progress_bar(const char *prefix, double percentage); void clear_progress_bar(const char *prefix); +void draw_progress_bar_unbuffered(const char *prefix, double percentage); +void clear_progress_bar_unbuffered(const char *prefix); diff --git a/src/sysupdate/sysupdated.c b/src/sysupdate/sysupdated.c index 4edfea937e1..9a078aa84a2 100644 --- a/src/sysupdate/sysupdated.c +++ b/src/sysupdate/sysupdated.c @@ -4,6 +4,7 @@ #include "sd-json.h" #include "build-path.h" +#include "bus-common-errors.h" #include "bus-error.h" #include "bus-get-properties.h" #include "bus-label.h" @@ -1044,8 +1045,8 @@ static int target_method_update_finished_early( /* Called when job finishes w/ a successful exit code, but before any work begins. * This happens when there is no candidate (i.e. we're already up-to-date), or * specified update is already installed. */ - return sd_bus_error_setf(error, "org.freedesktop.sysupdate1.NoCandidate", - "Job exited successfully with no work to do, assume already updated"); + return sd_bus_error_setf(error, BUS_ERROR_NO_UPDATE_CANDIDATE, + "Job exited successfully with no work to do, assume already updated"); } static int target_method_update_detach(sd_bus_message *msg, const Job *j) { diff --git a/src/sysupdate/updatectl.c b/src/sysupdate/updatectl.c index d5f74bff3ef..c298b244641 100644 --- a/src/sysupdate/updatectl.c +++ b/src/sysupdate/updatectl.c @@ -13,6 +13,7 @@ #include "bus-map-properties.h" #include "bus-util.h" #include "errno-list.h" +#include "fileio.h" #include "format-table.h" #include "json-util.h" #include "main-func.h" @@ -775,6 +776,7 @@ static int verb_check(int argc, char **argv, void *userdata) { } #define UPDATE_PROGRESS_FAILED INT_MIN +#define UPDATE_PROGRESS_DONE INT_MAX /* Make sure it doesn't overlap w/ errno values */ assert_cc(UPDATE_PROGRESS_FAILED < -ERRNO_MAX); @@ -794,6 +796,11 @@ static int update_render_progress(sd_event_source *source, void *userdata) { if (n == 0) return 0; + /* We're outputting lots of small strings to STDERR, which is unbuffered by default. So let's turn + * on full buffering, so we pass this all to the TTY in one go, to make things more efficient */ + char buffer[LONG_LINE_MAX]; + setvbuf(stderr, buffer, _IOFBF, sizeof(buffer)); + if (!terminal_is_dumb()) { for (size_t i = 0; i <= n; i++) fputs("\n", stderr); /* Possibly scroll the terminal to make room (including total)*/ @@ -808,24 +815,36 @@ static int update_render_progress(sd_event_source *source, void *userdata) { int progress = PTR_TO_INT(p); if (progress == UPDATE_PROGRESS_FAILED) { - fprintf(stderr, "%s %s\n", RED_CROSS_MARK(), target); + clear_progress_bar_unbuffered(target); + fprintf(stderr, "%s: %s Unknown failure\n", target, RED_CROSS_MARK()); total += 100; } else if (progress == -EALREADY) { - fprintf(stderr, "%s %s (Already up-to-date)\n", GREEN_CHECK_MARK(), target); + clear_progress_bar_unbuffered(target); + fprintf(stderr, "%s: %s Already up-to-date\n", target, GREEN_CHECK_MARK()); n--; /* Don't consider this target in the total */ } else if (progress < 0) { - fprintf(stderr, "%s %s (%s)\n", RED_CROSS_MARK(), target, STRERROR(progress)); + clear_progress_bar_unbuffered(target); + fprintf(stderr, "%s: %s %s\n", target, RED_CROSS_MARK(), STRERROR(progress)); + total += 100; + } else if (progress == UPDATE_PROGRESS_DONE) { + clear_progress_bar_unbuffered(target); + fprintf(stderr, "%s: %s Done\n", target, GREEN_CHECK_MARK()); total += 100; } else { - draw_progress_bar(target, progress); + draw_progress_bar_unbuffered(target, progress); fputs("\n", stderr); total += progress; } } if (n > 1) { - draw_progress_bar("TOTAL", (double) total / n); - fputs("\n", stderr); + if (exiting) + clear_progress_bar_unbuffered(target); + else { + draw_progress_bar_unbuffered("Total", (double) total / n); + if (terminal_is_dumb()) + fputs("\n", stderr); + } } if (!terminal_is_dumb()) { @@ -837,6 +856,7 @@ static int update_render_progress(sd_event_source *source, void *userdata) { fputs("------\n", stderr); fflush(stderr); + setvbuf(stderr, NULL, _IONBF, 0); /* Disable buffering again */ return 0; } @@ -895,7 +915,7 @@ static int update_finished(sd_bus_message *m, void *userdata, sd_bus_error *erro } if (status == 0) /* success */ - status = 100; + status = UPDATE_PROGRESS_DONE; else if (status > 0) /* exit status without errno */ status = UPDATE_PROGRESS_FAILED; /* i.e. EXIT_FAILURE */ /* else errno */ diff --git a/src/test/test-progress-bar.c b/src/test/test-progress-bar.c index b47adf0c289..abc1d292dcb 100644 --- a/src/test/test-progress-bar.c +++ b/src/test/test-progress-bar.c @@ -4,7 +4,7 @@ #include "random-util.h" #include "tests.h" -#define PROGRESS_PREFIX "test: " +#define PROGRESS_PREFIX "test:" TEST(progress_bar) {