]> git.ozlabs.org Git - petitboot/blobdiff - discover/paths.c
discover: Don't depend on tftp failure for type detection
[petitboot] / discover / paths.c
index d95e359e9f170b6a69e925a9002bdbe512818ec3..82a82b15125c7b2317d8d95d54fc784783af8d01 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <talloc/talloc.h>
 #include <system/system.h>
+#include <process/process.h>
 #include <url/url.h>
 #include <log/log.h>
 
 
 #define DEVICE_MOUNT_BASE (LOCAL_STATE_DIR "/petitboot/mnt")
 
+struct load_url_async_data {
+       load_url_callback url_cb;
+       void *ctx;
+};
+
 const char *mount_base(void)
 {
        return DEVICE_MOUNT_BASE;
@@ -48,46 +54,69 @@ static char *local_name(void *ctx)
        return ret;
 }
 
+static void load_url_exit_cb(struct process *process)
+{
+       struct load_url_async_data *url_data = process->data;
+
+       pb_log("The download client '%s' [pid %d] exited, rc %d\n",
+                       process->path, process->pid, process->exit_status);
+
+       url_data->url_cb(url_data->ctx, process->exit_status);
+
+       process_release(process);
+}
+
 /**
  * pb_load_nfs - Mounts the NFS export and returns the local file path.
  *
  * Returns the local file path in a talloc'ed character string on success,
  * or NULL on error.
  */
-static char *load_nfs(void *ctx, struct pb_url *url)
+static char *load_nfs(void *ctx, struct pb_url *url,
+               struct load_url_async_data *url_data)
 {
+       char *local, *opts;
        int result;
-       const char *argv[8];
-       const char **p;
-       char *local;
-       char *opts;
+       struct process *process;
+       const char *argv[] = {
+                       pb_system_apps.mount,
+                       "-t", "nfs",
+                       NULL,
+                       url->host,
+                       url->dir,
+                       NULL,
+                       NULL,
+       };
 
        local = local_name(ctx);
-
        if (!local)
                return NULL;
+       argv[6] = local;
 
        result = pb_mkdir_recursive(local);
-
        if (result)
                goto fail;
 
        opts = talloc_strdup(NULL, "ro,nolock,nodiratime");
+       argv[3] = opts;
 
        if (url->port)
                opts = talloc_asprintf_append(opts, ",port=%s", url->port);
 
-       p = argv;
-       *p++ = pb_system_apps.mount;    /* 1 */
-       *p++ = "-t";                    /* 2 */
-       *p++ = "nfs";                   /* 3 */
-       *p++ = opts;                    /* 4 */
-       *p++ = url->host;               /* 5 */
-       *p++ = url->dir;                /* 6 */
-       *p++ = local;                   /* 7 */
-       *p++ = NULL;                    /* 8 */
+       if (url_data) {
+               process = process_create(ctx);
 
-       result = pb_run_cmd(argv, 1, 0);
+               process->path = pb_system_apps.mount;
+               process->argv = argv;
+               process->exit_cb = load_url_exit_cb;
+               process->data = url_data;
+
+               result = process_run_async(process);
+               if (result)
+                       process_release(process);
+       } else {
+               result = process_run_simple_argv(ctx, argv);
+       }
 
        talloc_free(opts);
 
@@ -111,25 +140,41 @@ fail:
  * Returns the local file path in a talloc'ed character string on success,
  * or NULL on error.
  */
-static char *load_sftp(void *ctx, struct pb_url *url)
+static char *load_sftp(void *ctx, struct pb_url *url,
+               struct load_url_async_data *url_data)
 {
+       char *host_path, *local;
        int result;
-       const char *argv[4];
-       const char **p;
-       char *local;
+       struct process *process;
+       const char *argv[] = {
+                       pb_system_apps.sftp,
+                       NULL,
+                       NULL,
+                       NULL,
+       };
 
        local = local_name(ctx);
-
        if (!local)
                return NULL;
+       argv[2] = local;
 
-       p = argv;
-       *p++ = pb_system_apps.sftp;                                     /* 1 */
-       *p++ = talloc_asprintf(local, "%s:%s", url->host, url->path);   /* 2 */
-       *p++ = local;                                                   /* 3 */
-       *p++ = NULL;                                                    /* 4 */
+       host_path = talloc_asprintf(local, "%s:%s", url->host, url->path);
+       argv[1] = host_path;
+
+       if (url_data) {
+               process = process_create(ctx);
 
-       result = pb_run_cmd(argv, 1, 0);
+               process->path = pb_system_apps.sftp;
+               process->argv = argv;
+               process->exit_cb = load_url_exit_cb;
+               process->data = url_data;
+
+               result = process_run_async(process);
+               if (result)
+                       process_release(process);
+       } else {
+               result = process_run_simple_argv(ctx, argv);
+       }
 
        if (result)
                goto fail;
@@ -141,6 +186,41 @@ fail:
        return NULL;
 }
 
+static enum tftp_type check_tftp_type(void *ctx)
+{
+       const char *argv[] = { pb_system_apps.tftp, "-V", NULL };
+       struct process *process;
+       enum tftp_type type;
+
+       process = process_create(ctx);
+       process->path = pb_system_apps.tftp;
+       process->argv = argv;
+       process->keep_stdout = true;
+       process_run_sync(process);
+
+       if (!process->stdout_buf || process->stdout_len == 0) {
+               pb_log("Can't check TFTP client type!\n");
+               type = TFTP_TYPE_BROKEN;
+
+       } else if (memmem(process->stdout_buf, process->stdout_len,
+                               "tftp-hpa", strlen("tftp-hpa"))) {
+               pb_debug("Found TFTP client type: tftp-hpa\n");
+               type = TFTP_TYPE_HPA;
+
+       } else if (memmem(process->stdout_buf, process->stdout_len,
+                               "BusyBox", strlen("BusyBox"))) {
+               pb_debug("Found TFTP client type: BusyBox tftp\n");
+               type = TFTP_TYPE_BUSYBOX;
+
+       } else {
+               pb_log("Unknown TFTP client type!\n");
+               type = TFTP_TYPE_BROKEN;
+       }
+
+       process_release(process);
+       return type;
+}
+
 /**
  * pb_load_tftp - Loads a remote file via tftp and returns the local file path.
  *
@@ -148,53 +228,66 @@ fail:
  * or NULL on error.
  */
 
-static char *load_tftp(void *ctx, struct pb_url *url)
+static char *load_tftp(void *ctx, struct pb_url *url,
+               struct load_url_async_data *url_data)
 {
        int result;
        const char *argv[10];
        const char **p;
        char *local;
+       struct process *process;
 
-       local = local_name(ctx);
+       if (tftp_type == TFTP_TYPE_UNKNOWN)
+               tftp_type = check_tftp_type(ctx);
 
-       if (!local)
+       if (tftp_type == TFTP_TYPE_BROKEN)
                return NULL;
 
-       /* first try busybox tftp args */
-
-       p = argv;
-       *p++ = pb_system_apps.tftp;     /* 1 */
-       *p++ = "-g";                    /* 2 */
-       *p++ = "-l";                    /* 3 */
-       *p++ = local;                   /* 4 */
-       *p++ = "-r";                    /* 5 */
-       *p++ = url->path;               /* 6 */
-       *p++ = url->host;               /* 7 */
-       if (url->port)
-               *p++ = url->port;       /* 8 */
-       *p++ = NULL;                    /* 9 */
-
-       result = pb_run_cmd(argv, 1, 0);
+       local = local_name(ctx);
+       if (!local)
+               return NULL;
 
-       if (!result)
-               return local;
+       if (tftp_type == TFTP_TYPE_BUSYBOX) {
+               /* first try busybox tftp args */
+
+               p = argv;
+               *p++ = pb_system_apps.tftp;     /* 1 */
+               *p++ = "-g";                    /* 2 */
+               *p++ = "-l";                    /* 3 */
+               *p++ = local;                   /* 4 */
+               *p++ = "-r";                    /* 5 */
+               *p++ = url->path;               /* 6 */
+               *p++ = url->host;               /* 7 */
+               if (url->port)
+                       *p++ = url->port;       /* 8 */
+               *p++ = NULL;                    /* 9 */
+       } else {
+               p = argv;
+               *p++ = pb_system_apps.tftp;     /* 1 */
+               *p++ = "-m";                    /* 2 */
+               *p++ = "binary";                /* 3 */
+               *p++ = url->host;               /* 4 */
+               if (url->port)
+                       *p++ = url->port;       /* 5 */
+               *p++ = "-c";                    /* 6 */
+               *p++ = "get";                   /* 7 */
+               *p++ = url->path;               /* 8 */
+               *p++ = local;                   /* 9 */
+               *p++ = NULL;                    /* 10 */
+       }
 
-       /* next try tftp-hpa args */
+       if (url_data) {
+               process = process_create(ctx);
 
-       p = argv;
-       *p++ = pb_system_apps.tftp;     /* 1 */
-       *p++ = "-m";                    /* 2 */
-       *p++ = "binary";                /* 3 */
-       *p++ = url->host;               /* 4 */
-       if (url->port)
-               *p++ = url->port;       /* 5 */
-       *p++ = "-c";                    /* 6 */
-       *p++ = "get";                   /* 7 */
-       *p++ = url->path;               /* 8 */
-       *p++ = local;                   /* 9 */
-       *p++ = NULL;                    /* 10 */
+               process->path = pb_system_apps.tftp;
+               process->argv = argv;
+               process->exit_cb = load_url_exit_cb;
+               process->data = url_data;
 
-       result = pb_run_cmd(argv, 1, 0);
+               result = process_run_async(process);
+       } else {
+               result = process_run_simple_argv(ctx, argv);
+       }
 
        if (!result)
                return local;
@@ -215,12 +308,14 @@ enum wget_flags {
  * or NULL on error.
  */
 
-static char *load_wget(void *ctx, struct pb_url *url, enum wget_flags flags)
+static char *load_wget(void *ctx, struct pb_url *url, enum wget_flags flags,
+               struct load_url_async_data *url_data)
 {
        int result;
        const char *argv[7];
        const char **p;
        char *local;
+       struct process *process;
 
        local = local_name(ctx);
 
@@ -239,7 +334,20 @@ static char *load_wget(void *ctx, struct pb_url *url, enum wget_flags flags)
                *p++ = "--no-check-certificate";        /* 6 */
        *p++ = NULL;                                    /* 7 */
 
-       result = pb_run_cmd(argv, 1, 0);
+       if (url_data) {
+               process = process_create(ctx);
+
+               process->path = pb_system_apps.wget;
+               process->argv = argv;
+               process->exit_cb = load_url_exit_cb;
+               process->data = url_data;
+
+               result = process_run_async(process);
+               if (result)
+                       process_release(process);
+       } else {
+               result = process_run_simple_argv(ctx, argv);
+       }
 
        if (result)
                goto fail;
@@ -255,42 +363,55 @@ fail:
  * load_url - Loads a (possibly) remote URL and returns the local file
  * path.
  * @ctx: The talloc context to associate with the returned string.
- * @URL: The remote file URL.
+ * @url: The remote file URL.
  * @tempfile: An optional variable pointer to be set when a temporary local
  *  file is created.
+ * @url_cb: An optional callback pointer if the caller wants to load url
+ *  asynchronously.
  *
  * Returns the local file path in a talloc'ed character string on success,
  * or NULL on error.
  */
 
-char *load_url(void *ctx, struct pb_url *url, unsigned int *tempfile)
+char *load_url_async(void *ctx, struct pb_url *url, unsigned int *tempfile,
+               load_url_callback url_cb)
 {
        char *local;
        int tmp = 0;
+       struct load_url_async_data *url_data;
 
        if (!url)
                return NULL;
 
+       url_data = NULL;
+
+       if (url_cb) {
+               url_data = talloc_zero(ctx, struct load_url_async_data);
+               url_data->url_cb = url_cb;
+               url_data->ctx = ctx;
+       }
+
        switch (url->scheme) {
        case pb_url_ftp:
        case pb_url_http:
-               local = load_wget(ctx, url, 0);
+               local = load_wget(ctx, url, 0, url_data);
                tmp = !!local;
                break;
        case pb_url_https:
-               local = load_wget(ctx, url, wget_no_check_certificate);
+               local = load_wget(ctx, url, wget_no_check_certificate,
+                               url_data);
                tmp = !!local;
                break;
        case pb_url_nfs:
-               local = load_nfs(ctx, url);
+               local = load_nfs(ctx, url, url_data);
                tmp = !!local;
                break;
        case pb_url_sftp:
-               local = load_sftp(ctx, url);
+               local = load_sftp(ctx, url, url_data);
                tmp = !!local;
                break;
        case pb_url_tftp:
-               local = load_tftp(ctx, url);
+               local = load_tftp(ctx, url, url_data);
                tmp = !!local;
                break;
        default:
@@ -302,6 +423,10 @@ char *load_url(void *ctx, struct pb_url *url, unsigned int *tempfile)
        if (tempfile)
                *tempfile = tmp;
 
-       talloc_free(url);
        return local;
 }
+
+char *load_url(void *ctx, struct pb_url *url, unsigned int *tempfile)
+{
+       return load_url_async(ctx, url, tempfile, NULL);
+}