diff options
author | Samuel Mendoza-Jonas <sam@mendozajonas.com> | 2016-12-16 16:04:46 +1100 |
---|---|---|
committer | Samuel Mendoza-Jonas <sam@mendozajonas.com> | 2016-12-20 16:40:21 +1100 |
commit | dadebc9010718645789009a0fddbc6447b07f1da (patch) | |
tree | 15e3dd6a47f0cb41425f8551f81cbe31b1d69327 | |
parent | 78819395e5aa0dbd0c484f7a2512fcf04b87bbf2 (diff) | |
download | petitboot-dadebc9010718645789009a0fddbc6447b07f1da.zip petitboot-dadebc9010718645789009a0fddbc6447b07f1da.tar.gz |
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 <sam@mendozajonas.com>
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | 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 <log/log.h> #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); |