#endif
#include <assert.h>
+#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
-#include <sys/types.h>
+#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <talloc/talloc.h>
#include <system/system.h>
#include <process/process.h>
#include <url/url.h>
#include <log/log.h>
+#include "i18n/i18n.h"
#include "paths.h"
#include "device-handler.h"
+#include "sysinfo.h"
#define DEVICE_MOUNT_BASE (LOCAL_STATE_DIR "/petitboot/mnt")
+
+struct list pending_network_jobs;
+
+struct network_job {
+ struct load_task *task;
+ int flags;
+
+ struct list_item list;
+};
+
struct load_task {
struct pb_url *url;
struct process *process;
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;
#ifndef PETITBOOT_TEST
+#ifdef WITH_BUSYBOX
+static inline bool have_busybox(void) { return true; }
+#else
+static inline bool have_busybox(void) { return false; }
+#endif
+
static char *local_name(void *ctx)
{
char *ret, tmp[] = "/tmp/pb-XXXXXX";
} else {
result->status = LOAD_ERROR;
load_url_result_cleanup_local(result);
+ pb_debug("Download client stdout buffer:\n%s\n",
+ process->stdout_buf);
}
+ if (result->status == LOAD_OK && process->stdout_data)
+ device_handler_status_info(process->stdout_data,
+ _("Download complete: %s"), task->url->file);
+
/* The load callback may well free the ctx, which was the
* talloc parent of the task. Therefore, we want to do our cleanup
* before invoking it
}
}
- if (rc != 3)
+ if (rc != 3) {
percentage = size = 0;
+ suffix = ' ';
+ }
device_handler_status_download(handler, procinfo,
percentage, size, suffix);
*/
static void load_local(struct load_task *task)
{
+ struct load_url_result *result = task->result;
int rc;
rc = access(task->url->path, F_OK);
if (rc) {
- task->result->status = LOAD_ERROR;
+ result->status = LOAD_ERROR;
} else {
- task->result->local = talloc_strdup(task->result,
- task->url->path);
- task->result->status = LOAD_OK;
+ result->local = talloc_strdup(task->result, task->url->path);
+ result->status = LOAD_OK;
+ }
+
+ task->async_cb(task->result, task->async_data);
+}
+
+static void load_url_async_start_pending(struct load_task *task, int flags)
+{
+ pb_log("Starting pending job for %s\n", task->url->full);
+
+ switch (task->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:
+ /* Shouldn't be a need via this path but.. */
+ load_local(task);
+ break;
+ }
+
+ if (task->result->status == LOAD_ERROR) {
+ pb_log("Pending job failed for %s\n", task->url->full);
+ load_url_result_cleanup_local(task->result);
+ talloc_free(task->result);
+ talloc_free(task);
}
}
+void pending_network_jobs_start(void)
+{
+ struct network_job *job, *tmp;
+
+ if (!pending_network_jobs.head.next)
+ return;
+
+ list_for_each_entry_safe(&pending_network_jobs, job, tmp, list) {
+ load_url_async_start_pending(job->task, job->flags);
+ list_remove(&job->list);
+ }
+}
+
+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.
{
struct load_url_result *result;
struct load_task *task;
+ struct addrinfo *res;
int flags = 0;
if (!url)
task->process->keep_stdout = true;
}
+ /* If the url is remote but network is not yet available queue up this
+ * load for later */
+ if (url->scheme != pb_url_file) {
+ if (getaddrinfo(url->host, NULL, NULL, &res) != 0) {
+ 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;
+ }
+ freeaddrinfo(res);
+ }
+
switch (url->scheme) {
case pb_url_ftp:
case pb_url_http:
return NULL;
}
- if (!task->async)
+ if (!task->async || result->status == LOAD_OK)
talloc_free(task);
return result;