]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/import/pull.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / import / pull.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
72648326
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2014 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <getopt.h>
22
23#include "sd-event.h"
3f6fd1ba 24
b5efdb8a 25#include "alloc-util.h"
25300b5a 26#include "hostname-util.h"
85dbc41d 27#include "import-util.h"
3f6fd1ba 28#include "machine-image.h"
6bedfcbb 29#include "parse-util.h"
3f6fd1ba
LP
30#include "pull-raw.h"
31#include "pull-tar.h"
32#include "signal-util.h"
07630cea 33#include "string-util.h"
3f6fd1ba 34#include "verbs.h"
49cf4170 35#include "web-util.h"
72648326
LP
36
37static bool arg_force = false;
5f129649 38static const char *arg_image_root = "/var/lib/machines";
8f695058 39static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
9854730b 40static bool arg_settings = true;
91359193 41static bool arg_roothash = true;
91f4347e 42
3d7415f4
LP
43static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
44 log_notice("Transfer aborted.");
45 sd_event_exit(sd_event_source_get_event(s), EINTR);
46 return 0;
47}
48
dc2c282b 49static void on_tar_finished(TarPull *pull, int error, void *userdata) {
56ebfaf1 50 sd_event *event = userdata;
dc2c282b 51 assert(pull);
56ebfaf1
LP
52
53 if (error == 0)
54 log_info("Operation completed successfully.");
56ebfaf1 55
3d7415f4 56 sd_event_exit(event, abs(error));
56ebfaf1
LP
57}
58
59static int pull_tar(int argc, char *argv[], void *userdata) {
dc2c282b 60 _cleanup_(tar_pull_unrefp) TarPull *pull = NULL;
4afd3348 61 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
56ebfaf1
LP
62 const char *url, *local;
63 _cleanup_free_ char *l = NULL, *ll = NULL;
64 int r;
65
66 url = argv[1];
67 if (!http_url_is_valid(url)) {
68 log_error("URL '%s' is not valid.", url);
69 return -EINVAL;
70 }
71
72 if (argc >= 3)
73 local = argv[2];
74 else {
85dbc41d 75 r = import_url_last_component(url, &l);
56ebfaf1
LP
76 if (r < 0)
77 return log_error_errno(r, "Failed get final component of URL: %m");
78
79 local = l;
80 }
81
82 if (isempty(local) || streq(local, "-"))
83 local = NULL;
84
85 if (local) {
3d7415f4 86 r = tar_strip_suffixes(local, &ll);
56ebfaf1
LP
87 if (r < 0)
88 return log_oom();
89
90 local = ll;
91
92 if (!machine_name_is_valid(local)) {
93 log_error("Local image name '%s' is not valid.", local);
94 return -EINVAL;
95 }
96
97 if (!arg_force) {
98 r = image_find(local, NULL);
99 if (r < 0)
100 return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
101 else if (r > 0) {
92dfd88b 102 log_error("Image '%s' already exists.", local);
56ebfaf1
LP
103 return -EEXIST;
104 }
105 }
106
107 log_info("Pulling '%s', saving as '%s'.", url, local);
108 } else
109 log_info("Pulling '%s'.", url);
110
111 r = sd_event_default(&event);
112 if (r < 0)
113 return log_error_errno(r, "Failed to allocate event loop: %m");
114
72c0a2c2
LP
115 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
116 (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
117 (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
56ebfaf1 118
dc2c282b 119 r = tar_pull_new(&pull, event, arg_image_root, on_tar_finished, event);
56ebfaf1 120 if (r < 0)
dc2c282b 121 return log_error_errno(r, "Failed to allocate puller: %m");
56ebfaf1 122
9854730b 123 r = tar_pull_start(pull, url, local, arg_force, arg_verify, arg_settings);
56ebfaf1
LP
124 if (r < 0)
125 return log_error_errno(r, "Failed to pull image: %m");
126
127 r = sd_event_loop(event);
128 if (r < 0)
129 return log_error_errno(r, "Failed to run event loop: %m");
130
131 log_info("Exiting.");
3d7415f4 132 return -r;
56ebfaf1
LP
133}
134
dc2c282b 135static void on_raw_finished(RawPull *pull, int error, void *userdata) {
90199220 136 sd_event *event = userdata;
dc2c282b 137 assert(pull);
90199220
LP
138
139 if (error == 0)
140 log_info("Operation completed successfully.");
90199220 141
3d7415f4 142 sd_event_exit(event, abs(error));
edce2aed
LP
143}
144
aceac2f0 145static int pull_raw(int argc, char *argv[], void *userdata) {
dc2c282b 146 _cleanup_(raw_pull_unrefp) RawPull *pull = NULL;
4afd3348 147 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
edce2aed 148 const char *url, *local;
0d6e763b 149 _cleanup_free_ char *l = NULL, *ll = NULL;
90199220
LP
150 int r;
151
152 url = argv[1];
a2e03378 153 if (!http_url_is_valid(url)) {
90199220
LP
154 log_error("URL '%s' is not valid.", url);
155 return -EINVAL;
156 }
157
8620a9a3
LP
158 if (argc >= 3)
159 local = argv[2];
160 else {
85dbc41d 161 r = import_url_last_component(url, &l);
0d6e763b
LP
162 if (r < 0)
163 return log_error_errno(r, "Failed get final component of URL: %m");
90199220 164
0d6e763b 165 local = l;
90199220
LP
166 }
167
8620a9a3
LP
168 if (isempty(local) || streq(local, "-"))
169 local = NULL;
90199220 170
8620a9a3 171 if (local) {
3d7415f4 172 r = raw_strip_suffixes(local, &ll);
edce2aed
LP
173 if (r < 0)
174 return log_oom();
175
0d6e763b 176 local = ll;
8620a9a3
LP
177
178 if (!machine_name_is_valid(local)) {
179 log_error("Local image name '%s' is not valid.", local);
180 return -EINVAL;
181 }
182
0d6e763b
LP
183 if (!arg_force) {
184 r = image_find(local, NULL);
185 if (r < 0)
186 return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
187 else if (r > 0) {
92dfd88b 188 log_error("Image '%s' already exists.", local);
0d6e763b 189 return -EEXIST;
8620a9a3 190 }
0d6e763b 191 }
90199220 192
8620a9a3
LP
193 log_info("Pulling '%s', saving as '%s'.", url, local);
194 } else
195 log_info("Pulling '%s'.", url);
90199220
LP
196
197 r = sd_event_default(&event);
198 if (r < 0)
199 return log_error_errno(r, "Failed to allocate event loop: %m");
200
72c0a2c2
LP
201 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
202 (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
203 (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
90199220 204
dc2c282b 205 r = raw_pull_new(&pull, event, arg_image_root, on_raw_finished, event);
90199220 206 if (r < 0)
dc2c282b 207 return log_error_errno(r, "Failed to allocate puller: %m");
90199220 208
91359193 209 r = raw_pull_start(pull, url, local, arg_force, arg_verify, arg_settings, arg_roothash);
90199220
LP
210 if (r < 0)
211 return log_error_errno(r, "Failed to pull image: %m");
212
213 r = sd_event_loop(event);
214 if (r < 0)
215 return log_error_errno(r, "Failed to run event loop: %m");
216
217 log_info("Exiting.");
3d7415f4 218 return -r;
90199220
LP
219}
220
72648326
LP
221static int help(int argc, char *argv[], void *userdata) {
222
223 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
587fec42 224 "Download container or virtual machine images.\n\n"
72648326
LP
225 " -h --help Show this help\n"
226 " --version Show package version\n"
91f4347e 227 " --force Force creation of image\n"
9854730b
LP
228 " --verify=MODE Verify downloaded image, one of: 'no',\n"
229 " 'checksum', 'signature'\n"
230 " --settings=BOOL Download settings file with image\n"
91359193 231 " --roothash=BOOL Download root hash file with image\n"
b43d75c3 232 " --image-root=PATH Image root directory\n\n"
72648326 233 "Commands:\n"
aa9bd499 234 " tar URL [NAME] Download a TAR image\n"
b43d75c3 235 " raw URL [NAME] Download a RAW image\n",
72648326
LP
236 program_invocation_short_name);
237
238 return 0;
239}
240
241static int parse_argv(int argc, char *argv[]) {
242
243 enum {
244 ARG_VERSION = 0x100,
245 ARG_FORCE,
087682d1 246 ARG_IMAGE_ROOT,
8f695058 247 ARG_VERIFY,
9854730b 248 ARG_SETTINGS,
91359193 249 ARG_ROOTHASH,
72648326
LP
250 };
251
252 static const struct option options[] = {
253 { "help", no_argument, NULL, 'h' },
254 { "version", no_argument, NULL, ARG_VERSION },
255 { "force", no_argument, NULL, ARG_FORCE },
087682d1 256 { "image-root", required_argument, NULL, ARG_IMAGE_ROOT },
8f695058 257 { "verify", required_argument, NULL, ARG_VERIFY },
9854730b 258 { "settings", required_argument, NULL, ARG_SETTINGS },
91359193 259 { "roothash", required_argument, NULL, ARG_ROOTHASH },
72648326
LP
260 {}
261 };
262
9854730b 263 int c, r;
72648326
LP
264
265 assert(argc >= 0);
266 assert(argv);
267
268 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
269
270 switch (c) {
271
272 case 'h':
7eeeb28e 273 return help(0, NULL, NULL);
72648326
LP
274
275 case ARG_VERSION:
3f6fd1ba 276 return version();
72648326
LP
277
278 case ARG_FORCE:
279 arg_force = true;
280 break;
281
087682d1
LP
282 case ARG_IMAGE_ROOT:
283 arg_image_root = optarg;
284 break;
285
8f695058
LP
286 case ARG_VERIFY:
287 arg_verify = import_verify_from_string(optarg);
288 if (arg_verify < 0) {
289 log_error("Invalid verification setting '%s'", optarg);
290 return -EINVAL;
291 }
292
293 break;
294
9854730b
LP
295 case ARG_SETTINGS:
296 r = parse_boolean(optarg);
297 if (r < 0)
298 return log_error_errno(r, "Failed to parse --settings= parameter '%s'", optarg);
299
300 arg_settings = r;
301 break;
302
91359193
LP
303 case ARG_ROOTHASH:
304 r = parse_boolean(optarg);
305 if (r < 0)
306 return log_error_errno(r, "Failed to parse --roothash= parameter '%s'", optarg);
307
308 arg_roothash = r;
309 break;
310
72648326
LP
311 case '?':
312 return -EINVAL;
313
314 default:
315 assert_not_reached("Unhandled option");
316 }
317
318 return 1;
319}
320
dc2c282b 321static int pull_main(int argc, char *argv[]) {
72648326 322
7eeeb28e 323 static const Verb verbs[] = {
aa9bd499
LP
324 { "help", VERB_ANY, VERB_ANY, 0, help },
325 { "tar", 2, 3, 0, pull_tar },
326 { "raw", 2, 3, 0, pull_raw },
72648326
LP
327 {}
328 };
329
330 return dispatch_verb(argc, argv, verbs, NULL);
331}
332
333int main(int argc, char *argv[]) {
334 int r;
335
336 setlocale(LC_ALL, "");
337 log_parse_environment();
338 log_open();
339
340 r = parse_argv(argc, argv);
341 if (r <= 0)
342 goto finish;
343
ce30c8dc 344 (void) ignore_signals(SIGPIPE, -1);
b6e676ce 345
dc2c282b 346 r = pull_main(argc, argv);
72648326
LP
347
348finish:
349 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
350}