a1f65ec10a03dfa68a7c6f7765b9f5e97d8cc4b5
[petitboot] / discover / paths.c
1 #define _GNU_SOURCE
2
3 #include <string.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6
7 #include <talloc/talloc.h>
8 #include <system/system.h>
9 #include <process/process.h>
10 #include <url/url.h>
11 #include <log/log.h>
12
13 #include "paths.h"
14
15 #define DEVICE_MOUNT_BASE (LOCAL_STATE_DIR "/petitboot/mnt")
16
17 struct load_url_async_data {
18         load_url_callback url_cb;
19         void *ctx;
20         int status;
21 };
22
23 const char *mount_base(void)
24 {
25         return DEVICE_MOUNT_BASE;
26 }
27
28 char *join_paths(void *alloc_ctx, const char *a, const char *b)
29 {
30         char *full_path;
31
32         full_path = talloc_array(alloc_ctx, char, strlen(a) + strlen(b) + 2);
33
34         strcpy(full_path, a);
35         if (b[0] != '/' && a[strlen(a) - 1] != '/')
36                 strcat(full_path, "/");
37         strcat(full_path, b);
38
39         return full_path;
40 }
41
42
43 static char *local_name(void *ctx)
44 {
45         char *tmp, *ret;
46
47         tmp = tempnam(NULL, "pb-");
48
49         if (!tmp)
50                 return NULL;
51
52         ret = talloc_strdup(ctx, tmp);
53         free(tmp);
54
55         return ret;
56 }
57
58 static void load_url_exit_cb(struct process *process)
59 {
60         struct load_url_async_data *url_data = process->data;
61
62         pb_log("The download client '%s' [pid %d] exited, rc %d\n",
63                         process->path, process->pid, process->exit_status);
64
65         if (!url_data->status)
66                 url_data->url_cb(url_data->ctx, &(url_data->status));
67
68         process_release(process);
69 }
70
71 /**
72  * pb_load_nfs - Mounts the NFS export and returns the local file path.
73  *
74  * Returns the local file path in a talloc'ed character string on success,
75  * or NULL on error.
76  */
77 static char *load_nfs(void *ctx, struct pb_url *url,
78                 struct load_url_async_data *url_data)
79 {
80         char *local, *opts;
81         int result;
82         struct process *process;
83         const char *argv[] = {
84                         pb_system_apps.mount,
85                         "-t", "nfs",
86                         NULL,
87                         url->host,
88                         url->dir,
89                         NULL,
90                         NULL,
91         };
92
93         local = local_name(ctx);
94         if (!local)
95                 return NULL;
96         argv[6] = local;
97
98         result = pb_mkdir_recursive(local);
99         if (result)
100                 goto fail;
101
102         opts = talloc_strdup(NULL, "ro,nolock,nodiratime");
103         argv[3] = opts;
104
105         if (url->port)
106                 opts = talloc_asprintf_append(opts, ",port=%s", url->port);
107
108         if (url_data) {
109                 process = process_create(ctx);
110
111                 process->path = pb_system_apps.mount;
112                 process->argv = argv;
113                 process->exit_cb = load_url_exit_cb;
114                 process->data = url_data;
115
116                 result = process_run_async(process);
117                 if (result)
118                         process_release(process);
119         } else {
120                 result = process_run_simple_argv(ctx, argv);
121         }
122
123         talloc_free(opts);
124
125         if (result)
126                 goto fail;
127
128         local = talloc_asprintf_append(local,  "/%s", url->path);
129         pb_log("%s: local '%s'\n", __func__, local);
130
131         return local;
132
133 fail:
134         pb_rmdir_recursive("/", local);
135         talloc_free(local);
136         return NULL;
137 }
138
139 /**
140  * pb_load_sftp - Loads a remote file via sftp and returns the local file path.
141  *
142  * Returns the local file path in a talloc'ed character string on success,
143  * or NULL on error.
144  */
145 static char *load_sftp(void *ctx, struct pb_url *url,
146                 struct load_url_async_data *url_data)
147 {
148         char *host_path, *local;
149         int result;
150         struct process *process;
151         const char *argv[] = {
152                         pb_system_apps.sftp,
153                         NULL,
154                         NULL,
155                         NULL,
156         };
157
158         local = local_name(ctx);
159         if (!local)
160                 return NULL;
161         argv[2] = local;
162
163         host_path = talloc_asprintf(local, "%s:%s", url->host, url->path);
164         argv[1] = host_path;
165
166         if (url_data) {
167                 process = process_create(ctx);
168
169                 process->path = pb_system_apps.sftp;
170                 process->argv = argv;
171                 process->exit_cb = load_url_exit_cb;
172                 process->data = url_data;
173
174                 result = process_run_async(process);
175                 if (result)
176                         process_release(process);
177         } else {
178                 result = process_run_simple_argv(ctx, argv);
179         }
180
181         if (result)
182                 goto fail;
183
184         return local;
185
186 fail:
187         talloc_free(local);
188         return NULL;
189 }
190
191 /**
192  * pb_load_tftp - Loads a remote file via tftp and returns the local file path.
193  *
194  * Returns the local file path in a talloc'ed character string on success,
195  * or NULL on error.
196  */
197
198 static char *load_tftp(void *ctx, struct pb_url *url,
199                 struct load_url_async_data *url_data)
200 {
201         int result;
202         const char *argv[10];
203         const char **p;
204         char *local;
205         struct process *process;
206
207         local = local_name(ctx);
208
209         if (!local)
210                 return NULL;
211
212         /* first try busybox tftp args */
213
214         p = argv;
215         *p++ = pb_system_apps.tftp;     /* 1 */
216         *p++ = "-g";                    /* 2 */
217         *p++ = "-l";                    /* 3 */
218         *p++ = local;                   /* 4 */
219         *p++ = "-r";                    /* 5 */
220         *p++ = url->path;               /* 6 */
221         *p++ = url->host;               /* 7 */
222         if (url->port)
223                 *p++ = url->port;       /* 8 */
224         *p++ = NULL;                    /* 9 */
225
226         if (url_data) {
227                 process = process_create(ctx);
228
229                 process->path = pb_system_apps.tftp;
230                 process->argv = argv;
231                 process->exit_cb = load_url_exit_cb;
232                 process->data = url_data;
233
234                 result = process_run_async(process);
235         } else {
236                 result = process_run_simple_argv(ctx, argv);
237         }
238
239         if (!result)
240                 return local;
241
242         /* next try tftp-hpa args */
243         p = argv;
244         *p++ = pb_system_apps.tftp;     /* 1 */
245         *p++ = "-m";                    /* 2 */
246         *p++ = "binary";                /* 3 */
247         *p++ = url->host;               /* 4 */
248         if (url->port)
249                 *p++ = url->port;       /* 5 */
250         *p++ = "-c";                    /* 6 */
251         *p++ = "get";                   /* 7 */
252         *p++ = url->path;               /* 8 */
253         *p++ = local;                   /* 9 */
254         *p++ = NULL;                    /* 10 */
255
256         if (url_data) {
257                 process->argv = argv;
258                 result = process_run_async(process);
259                 if (result)
260                         process_release(process);
261         } else {
262                 result = process_run_simple_argv(ctx, argv);
263         }
264
265         if (!result)
266                 return local;
267
268         talloc_free(local);
269         return NULL;
270 }
271
272 enum wget_flags {
273         wget_empty = 0,
274         wget_no_check_certificate = 1,
275 };
276
277 /**
278  * pb_load_wget - Loads a remote file via wget and returns the local file path.
279  *
280  * Returns the local file path in a talloc'ed character string on success,
281  * or NULL on error.
282  */
283
284 static char *load_wget(void *ctx, struct pb_url *url, enum wget_flags flags,
285                 struct load_url_async_data *url_data)
286 {
287         int result;
288         const char *argv[7];
289         const char **p;
290         char *local;
291         struct process *process;
292
293         local = local_name(ctx);
294
295         if (!local)
296                 return NULL;
297
298         p = argv;
299         *p++ = pb_system_apps.wget;                     /* 1 */
300 #if !defined(DEBUG)
301         *p++ = "--quiet";                               /* 2 */
302 #endif
303         *p++ = "-O";                                    /* 3 */
304         *p++ = local;                                   /* 4 */
305         *p++ = url->full;                               /* 5 */
306         if (flags & wget_no_check_certificate)
307                 *p++ = "--no-check-certificate";        /* 6 */
308         *p++ = NULL;                                    /* 7 */
309
310         if (url_data) {
311                 process = process_create(ctx);
312
313                 process->path = pb_system_apps.wget;
314                 process->argv = argv;
315                 process->exit_cb = load_url_exit_cb;
316                 process->data = url_data;
317
318                 result = process_run_async(process);
319                 if (result)
320                         process_release(process);
321         } else {
322                 result = process_run_simple_argv(ctx, argv);
323         }
324
325         if (result)
326                 goto fail;
327
328         return local;
329
330 fail:
331         talloc_free(local);
332         return NULL;
333 }
334
335 /**
336  * load_url - Loads a (possibly) remote URL and returns the local file
337  * path.
338  * @ctx: The talloc context to associate with the returned string.
339  * @url: The remote file URL.
340  * @tempfile: An optional variable pointer to be set when a temporary local
341  *  file is created.
342  * @url_cb: An optional callback pointer if the caller wants to load url
343  *  asynchronously.
344  *
345  * Returns the local file path in a talloc'ed character string on success,
346  * or NULL on error.
347  */
348
349 char *load_url_async(void *ctx, struct pb_url *url, unsigned int *tempfile,
350                 load_url_callback url_cb)
351 {
352         char *local;
353         int tmp = 0;
354         struct load_url_async_data *url_data;
355
356         if (!url)
357                 return NULL;
358
359         url_data = NULL;
360
361         if (url_cb) {
362                 url_data = talloc_zero(ctx, struct load_url_async_data);
363                 url_data->url_cb = url_cb;
364                 url_data->ctx = ctx;
365                 url_data->status = 0;
366         }
367
368         switch (url->scheme) {
369         case pb_url_ftp:
370         case pb_url_http:
371                 local = load_wget(ctx, url, 0, url_data);
372                 tmp = !!local;
373                 break;
374         case pb_url_https:
375                 local = load_wget(ctx, url, wget_no_check_certificate,
376                                 url_data);
377                 tmp = !!local;
378                 break;
379         case pb_url_nfs:
380                 local = load_nfs(ctx, url, url_data);
381                 tmp = !!local;
382                 break;
383         case pb_url_sftp:
384                 local = load_sftp(ctx, url, url_data);
385                 tmp = !!local;
386                 break;
387         case pb_url_tftp:
388                 local = load_tftp(ctx, url, url_data);
389                 tmp = !!local;
390                 break;
391         default:
392                 local = talloc_strdup(ctx, url->full);
393                 tmp = 0;
394                 break;
395         }
396
397         if (tempfile)
398                 *tempfile = tmp;
399
400         return local;
401 }
402
403 char *load_url(void *ctx, struct pb_url *url, unsigned int *tempfile)
404 {
405         return load_url_async(ctx, url, tempfile, NULL);
406 }