2 This file is part of systemd.
4 Copyright 2015 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 "export-raw.h"
26 #include "export-tar.h"
29 #include "hostname-util.h"
30 #include "import-util.h"
31 #include "machine-image.h"
32 #include "signal-util.h"
33 #include "string-util.h"
36 static ImportCompressType arg_compress
= IMPORT_COMPRESS_UNKNOWN
;
38 static void determine_compression_from_filename(const char *p
) {
40 if (arg_compress
!= IMPORT_COMPRESS_UNKNOWN
)
44 arg_compress
= IMPORT_COMPRESS_UNCOMPRESSED
;
48 if (endswith(p
, ".xz"))
49 arg_compress
= IMPORT_COMPRESS_XZ
;
50 else if (endswith(p
, ".gz"))
51 arg_compress
= IMPORT_COMPRESS_GZIP
;
52 else if (endswith(p
, ".bz2"))
53 arg_compress
= IMPORT_COMPRESS_BZIP2
;
55 arg_compress
= IMPORT_COMPRESS_UNCOMPRESSED
;
58 static int interrupt_signal_handler(sd_event_source
*s
, const struct signalfd_siginfo
*si
, void *userdata
) {
59 log_notice("Transfer aborted.");
60 sd_event_exit(sd_event_source_get_event(s
), EINTR
);
64 static void on_tar_finished(TarExport
*export
, int error
, void *userdata
) {
65 sd_event
*event
= userdata
;
69 log_info("Operation completed successfully.");
71 sd_event_exit(event
, abs(error
));
74 static int export_tar(int argc
, char *argv
[], void *userdata
) {
75 _cleanup_(tar_export_unrefp
) TarExport
*export
= NULL
;
76 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
77 _cleanup_(image_unrefp
) Image
*image
= NULL
;
78 const char *path
= NULL
, *local
= NULL
;
79 _cleanup_close_
int open_fd
= -1;
82 if (machine_name_is_valid(argv
[1])) {
83 r
= image_find(argv
[1], &image
);
85 return log_error_errno(r
, "Failed to look for machine %s: %m", argv
[1]);
87 log_error("Machine image %s not found.", argv
[1]);
97 if (isempty(path
) || streq(path
, "-"))
100 determine_compression_from_filename(path
);
103 open_fd
= open(path
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_CLOEXEC
|O_NOCTTY
, 0666);
105 return log_error_errno(errno
, "Failed to open tar image for export: %m");
109 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local
, path
, import_compress_type_to_string(arg_compress
));
111 _cleanup_free_
char *pretty
= NULL
;
115 (void) readlink_malloc("/proc/self/fd/1", &pretty
);
116 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local
, strna(pretty
), import_compress_type_to_string(arg_compress
));
119 r
= sd_event_default(&event
);
121 return log_error_errno(r
, "Failed to allocate event loop: %m");
123 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
124 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, interrupt_signal_handler
, NULL
);
125 (void) sd_event_add_signal(event
, NULL
, SIGINT
, interrupt_signal_handler
, NULL
);
127 r
= tar_export_new(&export
, event
, on_tar_finished
, event
);
129 return log_error_errno(r
, "Failed to allocate exporter: %m");
131 r
= tar_export_start(export
, local
, fd
, arg_compress
);
133 return log_error_errno(r
, "Failed to export image: %m");
135 r
= sd_event_loop(event
);
137 return log_error_errno(r
, "Failed to run event loop: %m");
139 log_info("Exiting.");
143 static void on_raw_finished(RawExport
*export
, int error
, void *userdata
) {
144 sd_event
*event
= userdata
;
148 log_info("Operation completed successfully.");
150 sd_event_exit(event
, abs(error
));
153 static int export_raw(int argc
, char *argv
[], void *userdata
) {
154 _cleanup_(raw_export_unrefp
) RawExport
*export
= NULL
;
155 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
156 _cleanup_(image_unrefp
) Image
*image
= NULL
;
157 const char *path
= NULL
, *local
= NULL
;
158 _cleanup_close_
int open_fd
= -1;
161 if (machine_name_is_valid(argv
[1])) {
162 r
= image_find(argv
[1], &image
);
164 return log_error_errno(r
, "Failed to look for machine %s: %m", argv
[1]);
166 log_error("Machine image %s not found.", argv
[1]);
176 if (isempty(path
) || streq(path
, "-"))
179 determine_compression_from_filename(path
);
182 open_fd
= open(path
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_CLOEXEC
|O_NOCTTY
, 0666);
184 return log_error_errno(errno
, "Failed to open raw image for export: %m");
188 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local
, path
, import_compress_type_to_string(arg_compress
));
190 _cleanup_free_
char *pretty
= NULL
;
194 (void) readlink_malloc("/proc/self/fd/1", &pretty
);
195 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local
, strna(pretty
), import_compress_type_to_string(arg_compress
));
198 r
= sd_event_default(&event
);
200 return log_error_errno(r
, "Failed to allocate event loop: %m");
202 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
203 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, interrupt_signal_handler
, NULL
);
204 (void) sd_event_add_signal(event
, NULL
, SIGINT
, interrupt_signal_handler
, NULL
);
206 r
= raw_export_new(&export
, event
, on_raw_finished
, event
);
208 return log_error_errno(r
, "Failed to allocate exporter: %m");
210 r
= raw_export_start(export
, local
, fd
, arg_compress
);
212 return log_error_errno(r
, "Failed to export image: %m");
214 r
= sd_event_loop(event
);
216 return log_error_errno(r
, "Failed to run event loop: %m");
218 log_info("Exiting.");
222 static int help(int argc
, char *argv
[], void *userdata
) {
224 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
225 "Export container or virtual machine images.\n\n"
226 " -h --help Show this help\n"
227 " --version Show package version\n"
228 " --format=FORMAT Select format\n\n"
230 " tar NAME [FILE] Export a TAR image\n"
231 " raw NAME [FILE] Export a RAW image\n",
232 program_invocation_short_name
);
237 static int parse_argv(int argc
, char *argv
[]) {
244 static const struct option options
[] = {
245 { "help", no_argument
, NULL
, 'h' },
246 { "version", no_argument
, NULL
, ARG_VERSION
},
247 { "format", required_argument
, NULL
, ARG_FORMAT
},
256 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
261 return help(0, NULL
, NULL
);
267 if (streq(optarg
, "uncompressed"))
268 arg_compress
= IMPORT_COMPRESS_UNCOMPRESSED
;
269 else if (streq(optarg
, "xz"))
270 arg_compress
= IMPORT_COMPRESS_XZ
;
271 else if (streq(optarg
, "gzip"))
272 arg_compress
= IMPORT_COMPRESS_GZIP
;
273 else if (streq(optarg
, "bzip2"))
274 arg_compress
= IMPORT_COMPRESS_BZIP2
;
276 log_error("Unknown format: %s", optarg
);
285 assert_not_reached("Unhandled option");
291 static int export_main(int argc
, char *argv
[]) {
293 static const Verb verbs
[] = {
294 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
295 { "tar", 2, 3, 0, export_tar
},
296 { "raw", 2, 3, 0, export_raw
},
300 return dispatch_verb(argc
, argv
, verbs
, NULL
);
303 int main(int argc
, char *argv
[]) {
306 setlocale(LC_ALL
, "");
307 log_parse_environment();
310 r
= parse_argv(argc
, argv
);
314 (void) ignore_signals(SIGPIPE
, -1);
316 r
= export_main(argc
, argv
);
319 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;