From 78819395e5aa0dbd0c484f7a2512fcf04b87bbf2 Mon Sep 17 00:00:00 2001 From: Samuel Mendoza-Jonas Date: Fri, 16 Dec 2016 16:03:48 +1100 Subject: discover/device-handler: Add aggregated download progress updates Several processes run by Petitboot output progress information while running. Add device_handler_status_download() which process callers can call to register and update progress information (percentage and current size). A list of 'progress_info' structs holds this progress information, and on each call to device_handler_status_download() the information is combined and displayed as a single status update for readability. On completion device_handler_status_download_remove() is called to remove old progress information from the list. Signed-off-by: Samuel Mendoza-Jonas --- discover/device-handler.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++ discover/device-handler.h | 6 +++ 2 files changed, 123 insertions(+) diff --git a/discover/device-handler.c b/discover/device-handler.c index d038c5b..a73a7ce 100644 --- a/discover/device-handler.c +++ b/discover/device-handler.c @@ -46,6 +46,14 @@ enum default_priority { DEFAULT_PRIORITY_DISABLED = 0xff, }; +struct progress_info { + unsigned int percentage; + unsigned long size; /* size in bytes */ + + const struct process_info *procinfo; + struct list_item list; +}; + struct device_handler { struct discover_server *server; int dry_run; @@ -72,6 +80,9 @@ struct device_handler { struct boot_task *pending_boot; bool pending_boot_is_default; + + struct list progress; + unsigned int n_progress; }; static int mount_device(struct discover_device *dev); @@ -314,6 +325,8 @@ struct device_handler *device_handler_init(struct discover_server *server, list_init(&handler->unresolved_boot_options); + list_init(&handler->progress); + /* set up our mount point base */ pb_mkdir_recursive(mount_base()); @@ -487,6 +500,110 @@ void device_handler_status_err(struct device_handler *handler, va_end(ap); } +void device_handler_status_download(struct device_handler *handler, + const struct process_info *procinfo, + unsigned int percentage, unsigned int size, char suffix) +{ + struct progress_info *p, *progress = NULL; + uint64_t current_converted, current = 0; + const char *units = " kMGTP"; + unsigned long size_bytes; + char *update = NULL; + double total = 0; + unsigned int i; + int unit = 0; + + list_for_each_entry(&handler->progress, p, list) + if (p->procinfo == procinfo) + progress = p; + + if (!progress) { + pb_log("Registering new progress struct\n"); + progress = talloc_zero(handler, struct progress_info); + if (!progress) { + pb_log("Failed to allocate room for progress struct\n"); + return; + } + progress->procinfo = procinfo; + list_add(&handler->progress, &progress->list); + handler->n_progress++; + } + + size_bytes = size; + for (i = 0; i < strlen(units); i++) { + if (units[i] == suffix) + break; + } + + if (i >= strlen(units)) { + pb_log("Couldn't recognise suffix '%c'\n", suffix); + size_bytes = 0; + } else { + while (i--) + size_bytes <<= 10; + } + + progress->percentage = percentage; + progress->size = size_bytes; + + /* + * Aggregate the info we have and update status. If a progress struct + * has zero for both percentage and size we assume progress information + * is unavailable and fall back to a generic progress message. + */ + list_for_each_entry(&handler->progress, p, list) { + uint64_t c; + double t; + if (!p->percentage || !p->size) { + update = talloc_asprintf(handler, + _("%u downloads in progress..."), + handler->n_progress); + current = total = 0; + break; + } + + c = p->size; + t = (100 * c) / p->percentage; + + current += c; + total += t; + } + + if (total) { + current_converted = current; + while (current_converted >= 1000) { + current_converted >>= 10; + unit++; + } + update = talloc_asprintf(handler, + _("%u %s downloading: %.0f%% - %lu%cB"), + handler->n_progress, + ngettext("item", "items", handler->n_progress), + (current / total) * 100, current_converted, + units[unit]); + } + + if (!update) { + pb_log("%s: failed to allocate new status\n", __func__); + } else { + device_handler_status_info(handler, "%s\n", update); + talloc_free(update); + } +} + +void device_handler_status_download_remove(struct device_handler *handler, + struct process_info *procinfo) +{ + struct progress_info *p, *tmp; + + list_for_each_entry_safe(&handler->progress, p, tmp, list) + if (p->procinfo == procinfo) { + list_remove(&p->list); + talloc_free(p); + handler->n_progress--; + } +} + static void device_handler_boot_status_cb(void *arg, struct status *status) { device_handler_status(arg, status); diff --git a/discover/device-handler.h b/discover/device-handler.h index 874133d..133eff3 100644 --- a/discover/device-handler.h +++ b/discover/device-handler.h @@ -11,6 +11,7 @@ struct discover_device; struct discover_server; struct boot_option; struct boot_command; +struct process_info; struct event; struct device; struct waitset; @@ -108,6 +109,11 @@ void device_handler_status_dev_info(struct device_handler *handler, struct discover_device *dev, const char *fmt, ...); void device_handler_status_dev_err(struct device_handler *handler, struct discover_device *dev, const char *fmt, ...); +void device_handler_status_download(struct device_handler *handler, + const struct process_info *procinfo, + unsigned int percentage, unsigned int size, char suffix); +void device_handler_status_download_remove(struct device_handler *handler, + struct process_info *procinfo); struct discover_context *device_handler_discover_context_create( struct device_handler *handler, -- cgit v1.1