7 #include <talloc/talloc.h>
8 #include <system/system.h>
9 #include <process/process.h>
15 #define DEVICE_MOUNT_BASE (LOCAL_STATE_DIR "/petitboot/mnt")
19 struct process *process;
20 struct load_url_result *result;
22 load_url_complete async_cb;
26 const char *mount_base(void)
28 return DEVICE_MOUNT_BASE;
31 char *join_paths(void *alloc_ctx, const char *a, const char *b)
35 full_path = talloc_array(alloc_ctx, char, strlen(a) + strlen(b) + 2);
38 if (b[0] != '/' && a[strlen(a) - 1] != '/')
39 strcat(full_path, "/");
46 static char *local_name(void *ctx)
50 tmp = tempnam(NULL, "pb-");
55 ret = talloc_strdup(ctx, tmp);
61 static void load_url_result_cleanup_local(struct load_url_result *result)
63 if (result->cleanup_local)
64 unlink(result->local);
67 static void load_url_process_exit(struct process *process)
69 struct load_task *task = process->data;
70 struct load_url_result *result;
74 pb_debug("The download client '%s' [pid %d, url %s] exited, rc %d\n",
75 process->path, process->pid, task->url->full,
76 process->exit_status);
78 result = task->result;
79 data = task->async_data;
82 result->status = process->exit_status == 0 ? LOAD_OK : LOAD_ERROR;
83 if (result->status == LOAD_ERROR)
84 load_url_result_cleanup_local(result);
86 /* The load callback may well free the ctx, which was the
87 * talloc parent of the task. Therefore, we want to do our cleanup
90 process_release(process);
96 static void load_process_to_local_file(struct load_task *task,
97 const char **argv, int argv_local_idx)
101 task->result->local = local_name(task->result);
102 if (!task->result->local) {
103 task->result->status = LOAD_ERROR;
106 task->result->cleanup_local = true;
109 argv[argv_local_idx] = task->result->local;
111 task->process->argv = argv;
112 task->process->path = argv[0];
115 rc = process_run_async(task->process);
117 process_release(task->process);
118 task->process = NULL;
120 task->result->status = rc ? LOAD_ERROR : LOAD_ASYNC;
122 rc = process_run_sync(task->process);
123 task->result->status = rc ? LOAD_ERROR : LOAD_OK;
124 process_release(task->process);
125 task->process = NULL;
130 * pb_load_nfs - Create a mountpoint, set the local file within that
131 * mountpoint, and run the appropriate mount command
134 static void load_nfs(struct load_task *task)
136 char *mountpoint, *opts;
138 const char *argv[] = {
139 pb_system_apps.mount,
144 NULL, /* 6: mountpoint */
148 task->result->status = LOAD_ERROR;
149 mountpoint = local_name(task->result);
152 task->result->cleanup_local = true;
153 argv[6] = mountpoint;
155 rc = pb_mkdir_recursive(mountpoint);
159 opts = talloc_strdup(NULL, "ro,nolock,nodiratime");
163 opts = talloc_asprintf_append(opts, ",port=%s",
166 task->result->local = talloc_asprintf(task->result, "%s/%s",
170 task->process->path = pb_system_apps.mount;
171 task->process->argv = argv;
174 rc = process_run_async(task->process);
176 process_release(task->process);
177 task->process = NULL;
179 task->result->status = rc ? LOAD_ERROR : LOAD_ASYNC;
181 rc = process_run_sync(task->process);
182 task->result->status = rc ? LOAD_ERROR : LOAD_OK;
183 process_release(task->process);
184 task->process = NULL;
190 static void load_sftp(struct load_task *task)
192 const char *argv[] = {
194 NULL, /* 1: host:path */
195 NULL, /* 2: local file */
199 argv[1] = talloc_asprintf(task, "%s:%s",
200 task->url->host, task->url->path);
201 load_process_to_local_file(task, argv, 2);
204 static enum tftp_type check_tftp_type(void *ctx)
206 const char *argv[] = { pb_system_apps.tftp, "-V", NULL };
207 struct process *process;
210 process = process_create(ctx);
211 process->path = pb_system_apps.tftp;
212 process->argv = argv;
213 process->keep_stdout = true;
214 process_run_sync(process);
216 if (!process->stdout_buf || process->stdout_len == 0) {
217 pb_log("Can't check TFTP client type!\n");
218 type = TFTP_TYPE_BROKEN;
220 } else if (memmem(process->stdout_buf, process->stdout_len,
221 "tftp-hpa", strlen("tftp-hpa"))) {
222 pb_debug("Found TFTP client type: tftp-hpa\n");
223 type = TFTP_TYPE_HPA;
225 } else if (memmem(process->stdout_buf, process->stdout_len,
226 "BusyBox", strlen("BusyBox"))) {
227 pb_debug("Found TFTP client type: BusyBox tftp\n");
228 type = TFTP_TYPE_BUSYBOX;
231 pb_log("Unknown TFTP client type!\n");
232 type = TFTP_TYPE_BROKEN;
235 process_release(process);
239 static void load_tftp(struct load_task *task)
241 const char *port = "69";
242 const char *argv[10] = {
247 port = task->url->port;
249 if (tftp_type == TFTP_TYPE_UNKNOWN)
250 tftp_type = check_tftp_type(task);
252 if (tftp_type == TFTP_TYPE_BUSYBOX) {
255 argv[3] = NULL; /* 3: local file */
257 argv[5] = task->url->path;
258 argv[6] = task->url->host;
262 load_process_to_local_file(task, argv, 3);
264 } else if (tftp_type == TFTP_TYPE_HPA) {
267 argv[3] = task->url->host;
271 argv[7] = task->url->path;
272 argv[8] = NULL; /* 8: local file */
274 load_process_to_local_file(task, argv, 8);
277 task->result->status = LOAD_ERROR;
282 wget_no_check_certificate = 1,
286 * pb_load_wget - Loads a remote file via wget and returns the local file path.
288 * Returns the local file path in a talloc'ed character string on success,
292 static void load_wget(struct load_task *task, int flags)
294 const char *argv[] = {
297 NULL, /* 2: local file */
306 argv[i++] = "--quiet";
308 if (flags & wget_no_check_certificate)
309 argv[i++] = "--no-check-certificate";
311 argv[i] = task->url->full;
313 load_process_to_local_file(task, argv, 2);
317 * load_url - Loads a (possibly) remote URL and returns the local file
319 * @ctx: The talloc context to associate with the returned string.
320 * @url: The remote file URL.
321 * @tempfile: An optional variable pointer to be set when a temporary local
323 * @url_cb: An optional callback pointer if the caller wants to load url
326 * Returns the local file path in a talloc'ed character string on success,
330 struct load_url_result *load_url_async(void *ctx, struct pb_url *url,
331 load_url_complete async_cb, void *async_data)
333 struct load_url_result *result;
334 struct load_task *task;
339 task = talloc_zero(ctx, struct load_task);
341 task->async = async_cb != NULL;
342 task->result = talloc_zero(ctx, struct load_url_result);
343 task->process = process_create(task);
345 task->async_cb = async_cb;
346 task->async_data = async_data;
347 task->process->exit_cb = load_url_process_exit;
348 task->process->data = task;
351 switch (url->scheme) {
357 load_wget(task, wget_no_check_certificate);
369 task->result->local = talloc_strdup(task->result,
371 task->result->status = LOAD_OK;
375 result = task->result;
376 if (result->status == LOAD_ERROR) {
377 load_url_result_cleanup_local(task->result);
389 struct load_url_result *load_url(void *ctx, struct pb_url *url)
391 return load_url_async(ctx, url, NULL, NULL);