discover: Send options to client in order
[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 <url/url.h>
10 #include <log/log.h>
11
12 #include "paths.h"
13
14 #define DEVICE_MOUNT_BASE (LOCAL_STATE_DIR "/petitboot/mnt")
15
16 const char *mount_base(void)
17 {
18         return DEVICE_MOUNT_BASE;
19 }
20
21 char *join_paths(void *alloc_ctx, const char *a, const char *b)
22 {
23         char *full_path;
24
25         full_path = talloc_array(alloc_ctx, char, strlen(a) + strlen(b) + 2);
26
27         strcpy(full_path, a);
28         if (b[0] != '/' && a[strlen(a) - 1] != '/')
29                 strcat(full_path, "/");
30         strcat(full_path, b);
31
32         return full_path;
33 }
34
35
36 static char *local_name(void *ctx)
37 {
38         char *tmp, *ret;
39
40         tmp = tempnam(NULL, "pb-");
41
42         if (!tmp)
43                 return NULL;
44
45         ret = talloc_strdup(ctx, tmp);
46         free(tmp);
47
48         return ret;
49 }
50
51 /**
52  * pb_load_nfs - Mounts the NFS export and returns the local file path.
53  *
54  * Returns the local file path in a talloc'ed character string on success,
55  * or NULL on error.
56  */
57 static char *load_nfs(void *ctx, struct pb_url *url)
58 {
59         int result;
60         const char *argv[8];
61         const char **p;
62         char *local;
63         char *opts;
64
65         local = local_name(ctx);
66
67         if (!local)
68                 return NULL;
69
70         result = pb_mkdir_recursive(local);
71
72         if (result)
73                 goto fail;
74
75         opts = talloc_strdup(NULL, "ro,nolock,nodiratime");
76
77         if (url->port)
78                 opts = talloc_asprintf_append(opts, ",port=%s", url->port);
79
80         p = argv;
81         *p++ = pb_system_apps.mount;    /* 1 */
82         *p++ = "-t";                    /* 2 */
83         *p++ = "nfs";                   /* 3 */
84         *p++ = opts;                    /* 4 */
85         *p++ = url->host;               /* 5 */
86         *p++ = url->dir;                /* 6 */
87         *p++ = local;                   /* 7 */
88         *p++ = NULL;                    /* 8 */
89
90         result = pb_run_cmd(argv, 1, 0);
91
92         talloc_free(opts);
93
94         if (result)
95                 goto fail;
96
97         local = talloc_asprintf_append(local,  "/%s", url->path);
98         pb_log("%s: local '%s'\n", __func__, local);
99
100         return local;
101
102 fail:
103         pb_rmdir_recursive("/", local);
104         talloc_free(local);
105         return NULL;
106 }
107
108 /**
109  * pb_load_sftp - Loads a remote file via sftp and returns the local file path.
110  *
111  * Returns the local file path in a talloc'ed character string on success,
112  * or NULL on error.
113  */
114 static char *load_sftp(void *ctx, struct pb_url *url)
115 {
116         int result;
117         const char *argv[4];
118         const char **p;
119         char *local;
120
121         local = local_name(ctx);
122
123         if (!local)
124                 return NULL;
125
126         p = argv;
127         *p++ = pb_system_apps.sftp;                                     /* 1 */
128         *p++ = talloc_asprintf(local, "%s:%s", url->host, url->path);   /* 2 */
129         *p++ = local;                                                   /* 3 */
130         *p++ = NULL;                                                    /* 4 */
131
132         result = pb_run_cmd(argv, 1, 0);
133
134         if (result)
135                 goto fail;
136
137         return local;
138
139 fail:
140         talloc_free(local);
141         return NULL;
142 }
143
144 /**
145  * pb_load_tftp - Loads a remote file via tftp and returns the local file path.
146  *
147  * Returns the local file path in a talloc'ed character string on success,
148  * or NULL on error.
149  */
150
151 static char *load_tftp(void *ctx, struct pb_url *url)
152 {
153         int result;
154         const char *argv[10];
155         const char **p;
156         char *local;
157
158         local = local_name(ctx);
159
160         if (!local)
161                 return NULL;
162
163         /* first try busybox tftp args */
164
165         p = argv;
166         *p++ = pb_system_apps.tftp;     /* 1 */
167         *p++ = "-g";                    /* 2 */
168         *p++ = "-l";                    /* 3 */
169         *p++ = local;                   /* 4 */
170         *p++ = "-r";                    /* 5 */
171         *p++ = url->path;               /* 6 */
172         *p++ = url->host;               /* 7 */
173         if (url->port)
174                 *p++ = url->port;       /* 8 */
175         *p++ = NULL;                    /* 9 */
176
177         result = pb_run_cmd(argv, 1, 0);
178
179         if (!result)
180                 return local;
181
182         /* next try tftp-hpa args */
183
184         p = argv;
185         *p++ = pb_system_apps.tftp;     /* 1 */
186         *p++ = "-m";                    /* 2 */
187         *p++ = "binary";                /* 3 */
188         *p++ = url->host;               /* 4 */
189         if (url->port)
190                 *p++ = url->port;       /* 5 */
191         *p++ = "-c";                    /* 6 */
192         *p++ = "get";                   /* 7 */
193         *p++ = url->path;               /* 8 */
194         *p++ = local;                   /* 9 */
195         *p++ = NULL;                    /* 10 */
196
197         result = pb_run_cmd(argv, 1, 0);
198
199         if (!result)
200                 return local;
201
202         talloc_free(local);
203         return NULL;
204 }
205
206 enum wget_flags {
207         wget_empty = 0,
208         wget_no_check_certificate = 1,
209 };
210
211 /**
212  * pb_load_wget - Loads a remote file via wget and returns the local file path.
213  *
214  * Returns the local file path in a talloc'ed character string on success,
215  * or NULL on error.
216  */
217
218 static char *load_wget(void *ctx, struct pb_url *url, enum wget_flags flags)
219 {
220         int result;
221         const char *argv[7];
222         const char **p;
223         char *local;
224
225         local = local_name(ctx);
226
227         if (!local)
228                 return NULL;
229
230         p = argv;
231         *p++ = pb_system_apps.wget;                     /* 1 */
232 #if !defined(DEBUG)
233         *p++ = "--quiet";                               /* 2 */
234 #endif
235         *p++ = "-O";                                    /* 3 */
236         *p++ = local;                                   /* 4 */
237         *p++ = url->full;                               /* 5 */
238         if (flags & wget_no_check_certificate)
239                 *p++ = "--no-check-certificate";        /* 6 */
240         *p++ = NULL;                                    /* 7 */
241
242         result = pb_run_cmd(argv, 1, 0);
243
244         if (result)
245                 goto fail;
246
247         return local;
248
249 fail:
250         talloc_free(local);
251         return NULL;
252 }
253
254 /**
255  * load_url - Loads a (possibly) remote URL and returns the local file
256  * path.
257  * @ctx: The talloc context to associate with the returned string.
258  * @URL: The remote file URL.
259  * @tempfile: An optional variable pointer to be set when a temporary local
260  *  file is created.
261  *
262  * Returns the local file path in a talloc'ed character string on success,
263  * or NULL on error.
264  */
265
266 char *load_url(void *ctx, struct pb_url *url, unsigned int *tempfile)
267 {
268         char *local;
269         int tmp = 0;
270
271         if (!url)
272                 return NULL;
273
274         switch (url->scheme) {
275         case pb_url_ftp:
276         case pb_url_http:
277                 local = load_wget(ctx, url, 0);
278                 tmp = !!local;
279                 break;
280         case pb_url_https:
281                 local = load_wget(ctx, url, wget_no_check_certificate);
282                 tmp = !!local;
283                 break;
284         case pb_url_nfs:
285                 local = load_nfs(ctx, url);
286                 tmp = !!local;
287                 break;
288         case pb_url_sftp:
289                 local = load_sftp(ctx, url);
290                 tmp = !!local;
291                 break;
292         case pb_url_tftp:
293                 local = load_tftp(ctx, url);
294                 tmp = !!local;
295                 break;
296         default:
297                 local = talloc_strdup(ctx, url->full);
298                 tmp = 0;
299                 break;
300         }
301
302         if (tempfile)
303                 *tempfile = tmp;
304
305         talloc_free(url);
306         return local;
307 }