1 /* SPDX-License-Identifier: LGPL-2.1+ */
8 #include "alloc-util.h"
9 #include "hostname-util.h"
10 #include "import-util.h"
11 #include "machine-image.h"
12 #include "main-func.h"
13 #include "parse-util.h"
16 #include "signal-util.h"
17 #include "string-util.h"
21 static bool arg_force
= false;
22 static const char *arg_image_root
= "/var/lib/machines";
23 static ImportVerify arg_verify
= IMPORT_VERIFY_SIGNATURE
;
24 static bool arg_settings
= true;
25 static bool arg_roothash
= true;
27 static int interrupt_signal_handler(sd_event_source
*s
, const struct signalfd_siginfo
*si
, void *userdata
) {
28 log_notice("Transfer aborted.");
29 sd_event_exit(sd_event_source_get_event(s
), EINTR
);
33 static void on_tar_finished(TarPull
*pull
, int error
, void *userdata
) {
34 sd_event
*event
= userdata
;
38 log_info("Operation completed successfully.");
40 sd_event_exit(event
, abs(error
));
43 static int pull_tar(int argc
, char *argv
[], void *userdata
) {
44 _cleanup_(tar_pull_unrefp
) TarPull
*pull
= NULL
;
45 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
46 const char *url
, *local
;
47 _cleanup_free_
char *l
= NULL
, *ll
= NULL
;
51 if (!http_url_is_valid(url
)) {
52 log_error("URL '%s' is not valid.", url
);
59 r
= import_url_last_component(url
, &l
);
61 return log_error_errno(r
, "Failed get final component of URL: %m");
66 if (isempty(local
) || streq(local
, "-"))
70 r
= tar_strip_suffixes(local
, &ll
);
76 if (!machine_name_is_valid(local
)) {
77 log_error("Local image name '%s' is not valid.", local
);
82 r
= image_find(IMAGE_MACHINE
, local
, NULL
);
85 return log_error_errno(r
, "Failed to check whether image '%s' exists: %m", local
);
87 log_error("Image '%s' already exists.", local
);
92 log_info("Pulling '%s', saving as '%s'.", url
, local
);
94 log_info("Pulling '%s'.", url
);
96 r
= sd_event_default(&event
);
98 return log_error_errno(r
, "Failed to allocate event loop: %m");
100 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
101 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, interrupt_signal_handler
, NULL
);
102 (void) sd_event_add_signal(event
, NULL
, SIGINT
, interrupt_signal_handler
, NULL
);
104 r
= tar_pull_new(&pull
, event
, arg_image_root
, on_tar_finished
, event
);
106 return log_error_errno(r
, "Failed to allocate puller: %m");
108 r
= tar_pull_start(pull
, url
, local
, arg_force
, arg_verify
, arg_settings
);
110 return log_error_errno(r
, "Failed to pull image: %m");
112 r
= sd_event_loop(event
);
114 return log_error_errno(r
, "Failed to run event loop: %m");
116 log_info("Exiting.");
120 static void on_raw_finished(RawPull
*pull
, int error
, void *userdata
) {
121 sd_event
*event
= userdata
;
125 log_info("Operation completed successfully.");
127 sd_event_exit(event
, abs(error
));
130 static int pull_raw(int argc
, char *argv
[], void *userdata
) {
131 _cleanup_(raw_pull_unrefp
) RawPull
*pull
= NULL
;
132 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
133 const char *url
, *local
;
134 _cleanup_free_
char *l
= NULL
, *ll
= NULL
;
138 if (!http_url_is_valid(url
)) {
139 log_error("URL '%s' is not valid.", url
);
146 r
= import_url_last_component(url
, &l
);
148 return log_error_errno(r
, "Failed get final component of URL: %m");
153 if (isempty(local
) || streq(local
, "-"))
157 r
= raw_strip_suffixes(local
, &ll
);
163 if (!machine_name_is_valid(local
)) {
164 log_error("Local image name '%s' is not valid.", local
);
169 r
= image_find(IMAGE_MACHINE
, local
, NULL
);
172 return log_error_errno(r
, "Failed to check whether image '%s' exists: %m", local
);
174 log_error("Image '%s' already exists.", local
);
179 log_info("Pulling '%s', saving as '%s'.", url
, local
);
181 log_info("Pulling '%s'.", url
);
183 r
= sd_event_default(&event
);
185 return log_error_errno(r
, "Failed to allocate event loop: %m");
187 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
188 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, interrupt_signal_handler
, NULL
);
189 (void) sd_event_add_signal(event
, NULL
, SIGINT
, interrupt_signal_handler
, NULL
);
191 r
= raw_pull_new(&pull
, event
, arg_image_root
, on_raw_finished
, event
);
193 return log_error_errno(r
, "Failed to allocate puller: %m");
195 r
= raw_pull_start(pull
, url
, local
, arg_force
, arg_verify
, arg_settings
, arg_roothash
);
197 return log_error_errno(r
, "Failed to pull image: %m");
199 r
= sd_event_loop(event
);
201 return log_error_errno(r
, "Failed to run event loop: %m");
203 log_info("Exiting.");
207 static int help(int argc
, char *argv
[], void *userdata
) {
209 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
210 "Download container or virtual machine images.\n\n"
211 " -h --help Show this help\n"
212 " --version Show package version\n"
213 " --force Force creation of image\n"
214 " --verify=MODE Verify downloaded image, one of: 'no',\n"
215 " 'checksum', 'signature'\n"
216 " --settings=BOOL Download settings file with image\n"
217 " --roothash=BOOL Download root hash file with image\n"
218 " --image-root=PATH Image root directory\n\n"
220 " tar URL [NAME] Download a TAR image\n"
221 " raw URL [NAME] Download a RAW image\n",
222 program_invocation_short_name
);
227 static int parse_argv(int argc
, char *argv
[]) {
238 static const struct option options
[] = {
239 { "help", no_argument
, NULL
, 'h' },
240 { "version", no_argument
, NULL
, ARG_VERSION
},
241 { "force", no_argument
, NULL
, ARG_FORCE
},
242 { "image-root", required_argument
, NULL
, ARG_IMAGE_ROOT
},
243 { "verify", required_argument
, NULL
, ARG_VERIFY
},
244 { "settings", required_argument
, NULL
, ARG_SETTINGS
},
245 { "roothash", required_argument
, NULL
, ARG_ROOTHASH
},
254 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
259 return help(0, NULL
, NULL
);
269 arg_image_root
= optarg
;
273 arg_verify
= import_verify_from_string(optarg
);
275 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
276 "Invalid verification setting '%s'", optarg
);
281 r
= parse_boolean(optarg
);
283 return log_error_errno(r
, "Failed to parse --settings= parameter '%s': %m", optarg
);
289 r
= parse_boolean(optarg
);
291 return log_error_errno(r
, "Failed to parse --roothash= parameter '%s': %m", optarg
);
300 assert_not_reached("Unhandled option");
306 static int pull_main(int argc
, char *argv
[]) {
307 static const Verb verbs
[] = {
308 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
309 { "tar", 2, 3, 0, pull_tar
},
310 { "raw", 2, 3, 0, pull_raw
},
314 return dispatch_verb(argc
, argv
, verbs
, NULL
);
317 static int run(int argc
, char *argv
[]) {
320 setlocale(LC_ALL
, "");
321 log_parse_environment();
324 r
= parse_argv(argc
, argv
);
328 (void) ignore_signals(SIGPIPE
, -1);
330 return pull_main(argc
, argv
);
333 DEFINE_MAIN_FUNCTION(run
);