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