2 This file is part of systemd.
4 Copyright 2014 Lennart Poettering
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.
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.
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/>.
24 #include "alloc-util.h"
25 #include "hostname-util.h"
26 #include "import-util.h"
27 #include "machine-image.h"
28 #include "parse-util.h"
31 #include "signal-util.h"
32 #include "string-util.h"
36 static bool arg_force
= false;
37 static const char *arg_image_root
= "/var/lib/machines";
38 static ImportVerify arg_verify
= IMPORT_VERIFY_SIGNATURE
;
39 static bool arg_settings
= true;
41 static int interrupt_signal_handler(sd_event_source
*s
, const struct signalfd_siginfo
*si
, void *userdata
) {
42 log_notice("Transfer aborted.");
43 sd_event_exit(sd_event_source_get_event(s
), EINTR
);
47 static void on_tar_finished(TarPull
*pull
, int error
, void *userdata
) {
48 sd_event
*event
= userdata
;
52 log_info("Operation completed successfully.");
54 sd_event_exit(event
, abs(error
));
57 static int pull_tar(int argc
, char *argv
[], void *userdata
) {
58 _cleanup_(tar_pull_unrefp
) TarPull
*pull
= NULL
;
59 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
60 const char *url
, *local
;
61 _cleanup_free_
char *l
= NULL
, *ll
= NULL
;
65 if (!http_url_is_valid(url
)) {
66 log_error("URL '%s' is not valid.", url
);
73 r
= import_url_last_component(url
, &l
);
75 return log_error_errno(r
, "Failed get final component of URL: %m");
80 if (isempty(local
) || streq(local
, "-"))
84 r
= tar_strip_suffixes(local
, &ll
);
90 if (!machine_name_is_valid(local
)) {
91 log_error("Local image name '%s' is not valid.", local
);
96 r
= image_find(local
, NULL
);
98 return log_error_errno(r
, "Failed to check whether image '%s' exists: %m", local
);
100 log_error_errno(EEXIST
, "Image '%s' already exists.", local
);
105 log_info("Pulling '%s', saving as '%s'.", url
, local
);
107 log_info("Pulling '%s'.", url
);
109 r
= sd_event_default(&event
);
111 return log_error_errno(r
, "Failed to allocate event loop: %m");
113 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
114 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, interrupt_signal_handler
, NULL
);
115 (void) sd_event_add_signal(event
, NULL
, SIGINT
, interrupt_signal_handler
, NULL
);
117 r
= tar_pull_new(&pull
, event
, arg_image_root
, on_tar_finished
, event
);
119 return log_error_errno(r
, "Failed to allocate puller: %m");
121 r
= tar_pull_start(pull
, url
, local
, arg_force
, arg_verify
, arg_settings
);
123 return log_error_errno(r
, "Failed to pull image: %m");
125 r
= sd_event_loop(event
);
127 return log_error_errno(r
, "Failed to run event loop: %m");
129 log_info("Exiting.");
133 static void on_raw_finished(RawPull
*pull
, int error
, void *userdata
) {
134 sd_event
*event
= userdata
;
138 log_info("Operation completed successfully.");
140 sd_event_exit(event
, abs(error
));
143 static int pull_raw(int argc
, char *argv
[], void *userdata
) {
144 _cleanup_(raw_pull_unrefp
) RawPull
*pull
= NULL
;
145 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
146 const char *url
, *local
;
147 _cleanup_free_
char *l
= NULL
, *ll
= NULL
;
151 if (!http_url_is_valid(url
)) {
152 log_error("URL '%s' is not valid.", url
);
159 r
= import_url_last_component(url
, &l
);
161 return log_error_errno(r
, "Failed get final component of URL: %m");
166 if (isempty(local
) || streq(local
, "-"))
170 r
= raw_strip_suffixes(local
, &ll
);
176 if (!machine_name_is_valid(local
)) {
177 log_error("Local image name '%s' is not valid.", local
);
182 r
= image_find(local
, NULL
);
184 return log_error_errno(r
, "Failed to check whether image '%s' exists: %m", local
);
186 log_error_errno(EEXIST
, "Image '%s' already exists.", local
);
191 log_info("Pulling '%s', saving as '%s'.", url
, local
);
193 log_info("Pulling '%s'.", url
);
195 r
= sd_event_default(&event
);
197 return log_error_errno(r
, "Failed to allocate event loop: %m");
199 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
200 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, interrupt_signal_handler
, NULL
);
201 (void) sd_event_add_signal(event
, NULL
, SIGINT
, interrupt_signal_handler
, NULL
);
203 r
= raw_pull_new(&pull
, event
, arg_image_root
, on_raw_finished
, event
);
205 return log_error_errno(r
, "Failed to allocate puller: %m");
207 r
= raw_pull_start(pull
, url
, local
, arg_force
, arg_verify
, arg_settings
);
209 return log_error_errno(r
, "Failed to pull image: %m");
211 r
= sd_event_loop(event
);
213 return log_error_errno(r
, "Failed to run event loop: %m");
215 log_info("Exiting.");
219 static int help(int argc
, char *argv
[], void *userdata
) {
221 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
222 "Download container or virtual machine images.\n\n"
223 " -h --help Show this help\n"
224 " --version Show package version\n"
225 " --force Force creation of image\n"
226 " --verify=MODE Verify downloaded image, one of: 'no',\n"
227 " 'checksum', 'signature'\n"
228 " --settings=BOOL Download settings file with image\n"
229 " --image-root=PATH Image root directory\n\n"
231 " tar URL [NAME] Download a TAR image\n"
232 " raw URL [NAME] Download a RAW image\n",
233 program_invocation_short_name
);
238 static int parse_argv(int argc
, char *argv
[]) {
248 static const struct option options
[] = {
249 { "help", no_argument
, NULL
, 'h' },
250 { "version", no_argument
, NULL
, ARG_VERSION
},
251 { "force", no_argument
, NULL
, ARG_FORCE
},
252 { "image-root", required_argument
, NULL
, ARG_IMAGE_ROOT
},
253 { "verify", required_argument
, NULL
, ARG_VERIFY
},
254 { "settings", required_argument
, NULL
, ARG_SETTINGS
},
263 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
268 return help(0, NULL
, NULL
);
278 arg_image_root
= optarg
;
282 arg_verify
= import_verify_from_string(optarg
);
283 if (arg_verify
< 0) {
284 log_error("Invalid verification setting '%s'", optarg
);
291 r
= parse_boolean(optarg
);
293 return log_error_errno(r
, "Failed to parse --settings= parameter '%s'", optarg
);
302 assert_not_reached("Unhandled option");
308 static int pull_main(int argc
, char *argv
[]) {
310 static const Verb verbs
[] = {
311 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
312 { "tar", 2, 3, 0, pull_tar
},
313 { "raw", 2, 3, 0, pull_raw
},
317 return dispatch_verb(argc
, argv
, verbs
, NULL
);
320 int main(int argc
, char *argv
[]) {
323 setlocale(LC_ALL
, "");
324 log_parse_environment();
327 r
= parse_argv(argc
, argv
);
331 (void) ignore_signals(SIGPIPE
, -1);
333 r
= pull_main(argc
, argv
);
336 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;