+void pending_network_jobs_cancel(void)
+{
+ struct network_job *job, *tmp;
+
+ if (!pending_network_jobs.head.next)
+ return;
+
+ list_for_each_entry_safe(&pending_network_jobs, job, tmp, list)
+ talloc_free(job);
+ list_init(&pending_network_jobs);
+}
+
+static void pending_network_jobs_add(struct load_task *task, int flags)
+{
+ struct network_job *job;
+
+ if (!pending_network_jobs.head.next)
+ list_init(&pending_network_jobs);
+
+ job = talloc(task, struct network_job);
+ if (!job) {
+ pb_log("Failed to allocate space for pending job\n");
+ return;
+ }
+
+ job->task = task;
+ job->flags = flags;
+ list_add_tail(&pending_network_jobs, &job->list);
+}
+
+
+/**
+ * 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.
+ * @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.
+ */
+
+struct load_url_result *load_url_async(void *ctx, struct pb_url *url,
+ load_url_complete async_cb, void *async_data,
+ waiter_cb stdout_cb, void *stdout_data)
+{
+ struct load_url_result *result;
+ struct load_task *task;
+ int flags = 0;
+
+ if (!url)
+ return NULL;
+
+ task = talloc_zero(ctx, struct load_task);
+ task->url = url;
+ task->async = async_cb != NULL;
+ task->result = talloc_zero(ctx, struct load_url_result);
+ task->result->task = task;
+ task->result->url = url;
+ task->process = process_create(task);
+ if (task->async) {
+ task->async_cb = async_cb;
+ task->async_data = async_data;
+ task->process->exit_cb = load_url_process_exit;
+ task->process->data = task;
+ task->process->stdout_cb = stdout_cb;
+ 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;
+ task->process->keep_stdout = true;
+ }
+
+ /* If the url is remote but network is not yet available queue up this
+ * load for later */
+ if (!system_info_network_available() && url->scheme != pb_url_file) {
+ pb_log("load task for %s queued pending network\n", url->full);
+ pending_network_jobs_add(task, flags);
+ task->result->status = LOAD_ASYNC;
+ return task->result;
+ }
+
+ switch (url->scheme) {
+ case pb_url_ftp:
+ case pb_url_http:
+ load_wget(task, flags);
+ break;
+ case pb_url_https:
+ flags |= wget_no_check_certificate;
+ load_wget(task, flags);
+ break;
+ case pb_url_nfs:
+ load_nfs(task);
+ break;
+ case pb_url_sftp:
+ load_sftp(task);
+ break;
+ case pb_url_tftp:
+ load_tftp(task);
+ break;
+ default:
+ load_local(task);
+ break;
+ }
+
+ result = task->result;
+ if (result->status == LOAD_ERROR) {
+ load_url_result_cleanup_local(task->result);
+ talloc_free(result);
+ talloc_free(task);
+ return NULL;
+ }
+
+ if (!task->async || result->status == LOAD_OK)
+ talloc_free(task);
+
+ return result;
+}
+
+struct load_url_result *load_url(void *ctx, struct pb_url *url)
+{
+ return load_url_async(ctx, url, NULL, NULL, NULL, NULL);
+}
+
+void load_url_async_cancel(struct load_url_result *res)
+{
+ struct load_task *task = res->task;
+
+ /* the completion callback may have already been called; this clears
+ * res->task */
+ if (!task)
+ return;
+
+ if (res->status == LOAD_CANCELLED)
+ return;
+
+ assert(task->async);
+ assert(task->process);
+
+ res->status = LOAD_CANCELLED;
+ process_stop_async(task->process);
+}
+
+#else
+
+static void __attribute__((unused)) load_local(
+ struct load_task *task __attribute__((unused)))
+{
+}
+static void __attribute__((unused)) load_wget(
+ struct load_task *task __attribute__((unused)),
+ int flags __attribute__((unused)))
+{
+}
+static void __attribute__((unused)) load_tftp(
+ struct load_task *task __attribute__((unused)))
+{
+}
+static void __attribute__((unused)) load_sftp(
+ struct load_task *task __attribute__((unused)))
+{
+}
+static void __attribute__((unused)) load_nfs(
+ struct load_task *task __attribute__((unused)))
+{
+}
+static void __attribute__((unused)) load_url_process_exit(
+ struct process *process __attribute__((unused)))
+{