From dadebc9010718645789009a0fddbc6447b07f1da Mon Sep 17 00:00:00 2001 From: Samuel Mendoza-Jonas Date: Fri, 16 Dec 2016 16:04:46 +1100 Subject: [PATCH] discover/paths: Parse Busybox progress information Several busybox utilities (tftp and wget in particular) use a common format for progress bar output. Add a stdout callback that recognises this format and passes progress information to device_handler_status_download(). If Petitboot has been explicitly built with busybox support set busybox_progress_cb() as the default stdout callback for load_url_async(). Signed-off-by: Samuel Mendoza-Jonas --- configure.ac | 6 +++- discover/paths.c | 94 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 93 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 41560d1..1496054 100644 --- a/configure.ac +++ b/configure.ac @@ -242,7 +242,11 @@ AC_ARG_ENABLE( [], [enable_busybox=no] ) -#AM_CONDITIONAL([ENABLE_BUSYBOX], [test "x$enable_busybox" = "xyes"]) +AM_CONDITIONAL([ENABLE_BUSYBOX], [test "x$enable_busybox" = "xyes"]) +AS_IF([test "x$enable_busybox" = "xyes"], + [AC_DEFINE(WITH_BUSYBOX, 1, [Busybox environment enabled])], + [] +) AC_ARG_ENABLE( [mtd], diff --git a/discover/paths.c b/discover/paths.c index ad42b5b..0f102a2 100644 --- a/discover/paths.c +++ b/discover/paths.c @@ -16,6 +16,7 @@ #include #include "paths.h" +#include "device-handler.h" #define DEVICE_MOUNT_BASE (LOCAL_STATE_DIR "/petitboot/mnt") @@ -28,6 +29,15 @@ struct load_task { void *async_data; }; +static inline bool have_busybox(void) +{ +#ifdef WITH_BUSYBOX + return true; +#else + return false; +#endif +} + const char *mount_base(void) { return DEVICE_MOUNT_BASE; @@ -110,6 +120,66 @@ static void load_url_process_exit(struct process *process) cb(result, data); } +/* + * Callback to retrieve progress information from Busybox utilities. + * Busybox utilities use a common progress bar format which progress percentage + * and current size can be can be parsed from. + */ +static int busybox_progress_cb(void *arg) +{ + const char *busybox_fmt = "%*s %u%*[%* |]%u%c %*u:%*u:%*u ETA\n"; + struct process_info *procinfo = arg; + char *n, *s, suffix, *line = NULL; + struct device_handler *handler; + unsigned int percentage, size; + struct process *p; + int rc; + + if (!arg) + return -1; + + p = procinfo_get_process(procinfo); + handler = p->stdout_data; + + rc = process_stdout_custom(procinfo, &line); + + if (rc) { + /* Unregister ourselves from progress tracking */ + device_handler_status_download_remove(handler, procinfo); + } + + if (rc || !line) + return rc; + + rc = sscanf(line, busybox_fmt, &percentage, &size, &suffix); + + /* + * Many unrecognised lines are partial updates. If we see a partial + * line with a newline character, see if we can match a valid line + * at the end of stdout_buf + */ + if (rc != 3) { + n = strchr(line, '\n'); + if (n) + for (s = n - 1; s >= p->stdout_buf; s--) + if (*s == '\n') { + rc = sscanf(s + 1, busybox_fmt, + &percentage, &size, &suffix); + break; + } + } + + if (rc != 3) + percentage = size = 0; + + device_handler_status_download(handler, procinfo, + percentage, size, suffix); + + return 0; +} + + + static void load_process_to_local_file(struct load_task *task, const char **argv, int argv_local_idx) { @@ -300,8 +370,9 @@ static void load_tftp(struct load_task *task) } enum wget_flags { - wget_empty = 0, - wget_no_check_certificate = 1, + wget_empty = 0x1, + wget_no_check_certificate = 0x2, + wget_verbose = 0x4, }; /** @@ -324,10 +395,16 @@ static void load_wget(struct load_task *task, int flags) }; int i; + if (task->process->stdout_cb) + flags |= wget_verbose; + i = 3; -#if !defined(DEBUG) - argv[i++] = "--quiet"; +#if defined(DEBUG) + flags |= wget_verbose; #endif + if ((flags & wget_verbose) == 0) + argv[i++] = "--quiet"; + if (flags & wget_no_check_certificate) argv[i++] = "--no-check-certificate"; @@ -375,6 +452,7 @@ struct load_url_result *load_url_async(void *ctx, struct pb_url *url, { struct load_url_result *result; struct load_task *task; + int flags = 0; if (!url) return NULL; @@ -395,6 +473,9 @@ struct load_url_result *load_url_async(void *ctx, struct pb_url *url, task->process->stdout_data = stdout_data; } + if (!stdout_cb && stdout_data && have_busybox()) + task->process->stdout_cb = busybox_progress_cb; + /* Make sure we save output for any task that has a custom handler */ if (task->process->stdout_cb) { task->process->add_stderr = true; @@ -404,10 +485,11 @@ struct load_url_result *load_url_async(void *ctx, struct pb_url *url, switch (url->scheme) { case pb_url_ftp: case pb_url_http: - load_wget(task, 0); + load_wget(task, flags); break; case pb_url_https: - load_wget(task, wget_no_check_certificate); + flags |= wget_no_check_certificate; + load_wget(task, flags); break; case pb_url_nfs: load_nfs(task); -- 2.39.2