[PATCH 25/29] discover/device-handler: Add aggregated download progress updates
Samuel Mendoza-Jonas
sam at mendozajonas.com
Mon Dec 19 15:19:11 AEDT 2016
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 <sam at mendozajonas.com>
---
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 484608a..f3405f2 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());
@@ -486,6 +499,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_coverted, 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_coverted = current;
+ while (current_coverted >= 100000) {
+ current_coverted >>= 10;
+ unit++;
+ }
+ update = talloc_asprintf(handler,
+ _("%u %s downloading: %.2f%% - %lu%c,"),
+ handler->n_progress,
+ ngettext("item", "items", 2),
+ (current / total) * 100, current_coverted,
+ 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,
--
2.10.2
More information about the Petitboot
mailing list