discover/paths: Parse Busybox progress information
authorSamuel Mendoza-Jonas <sam@mendozajonas.com>
Fri, 16 Dec 2016 05:04:46 +0000 (16:04 +1100)
committerSamuel Mendoza-Jonas <sam@mendozajonas.com>
Tue, 20 Dec 2016 05:40:21 +0000 (16:40 +1100)
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>
configure.ac
discover/paths.c

index 41560d1aa237383177c14987965e5b55fe3c9090..1496054679191cd8d90c166cb69dd85ece5ce43e 100644 (file)
@@ -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],
index ad42b5b7760858e7cd3ab6d7217d855e91b72f15..0f102a222b76fac144fd35617366c0975eb3ff77 100644 (file)
@@ -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);