1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
9 #include "alloc-util.h"
11 #include "discover-image.h"
12 #include "export-raw.h"
13 #include "export-tar.h"
16 #include "hostname-util.h"
17 #include "import-common.h"
18 #include "import-util.h"
19 #include "main-func.h"
20 #include "signal-util.h"
21 #include "string-util.h"
22 #include "terminal-util.h"
25 static ImportCompressType arg_compress
= IMPORT_COMPRESS_UNKNOWN
;
26 static ImageClass arg_class
= IMAGE_MACHINE
;
28 static void determine_compression_from_filename(const char *p
) {
30 if (arg_compress
!= IMPORT_COMPRESS_UNKNOWN
)
34 arg_compress
= IMPORT_COMPRESS_UNCOMPRESSED
;
38 if (endswith(p
, ".xz"))
39 arg_compress
= IMPORT_COMPRESS_XZ
;
40 else if (endswith(p
, ".gz"))
41 arg_compress
= IMPORT_COMPRESS_GZIP
;
42 else if (endswith(p
, ".bz2"))
43 arg_compress
= IMPORT_COMPRESS_BZIP2
;
45 arg_compress
= IMPORT_COMPRESS_UNCOMPRESSED
;
48 static void on_tar_finished(TarExport
*export
, int error
, void *userdata
) {
49 sd_event
*event
= userdata
;
53 log_info("Operation completed successfully.");
55 sd_event_exit(event
, abs(error
));
58 static int export_tar(int argc
, char *argv
[], void *userdata
) {
59 _cleanup_(tar_export_unrefp
) TarExport
*export
= NULL
;
60 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
61 _cleanup_(image_unrefp
) Image
*image
= NULL
;
62 const char *path
= NULL
, *local
= NULL
;
63 _cleanup_close_
int open_fd
= -EBADF
;
66 if (hostname_is_valid(argv
[1], 0)) {
67 r
= image_find(arg_class
, argv
[1], NULL
, &image
);
69 return log_error_errno(r
, "Machine image %s not found.", argv
[1]);
71 return log_error_errno(r
, "Failed to look for machine %s: %m", argv
[1]);
79 path
= empty_or_dash_to_null(path
);
81 determine_compression_from_filename(path
);
84 open_fd
= open(path
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_CLOEXEC
|O_NOCTTY
, 0666);
86 return log_error_errno(errno
, "Failed to open tar image for export: %m");
90 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local
, path
, import_compress_type_to_string(arg_compress
));
92 _cleanup_free_
char *pretty
= NULL
;
96 (void) fd_get_path(fd
, &pretty
);
97 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local
, strna(pretty
), import_compress_type_to_string(arg_compress
));
100 r
= import_allocate_event_with_signals(&event
);
104 r
= tar_export_new(&export
, event
, on_tar_finished
, event
);
106 return log_error_errno(r
, "Failed to allocate exporter: %m");
108 r
= tar_export_start(export
, local
, fd
, arg_compress
);
110 return log_error_errno(r
, "Failed to export 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(RawExport
*export
, 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 export_raw(int argc
, char *argv
[], void *userdata
) {
131 _cleanup_(raw_export_unrefp
) RawExport
*export
= NULL
;
132 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
133 _cleanup_(image_unrefp
) Image
*image
= NULL
;
134 const char *path
= NULL
, *local
= NULL
;
135 _cleanup_close_
int open_fd
= -EBADF
;
138 if (hostname_is_valid(argv
[1], 0)) {
139 r
= image_find(arg_class
, argv
[1], NULL
, &image
);
141 return log_error_errno(r
, "Machine image %s not found.", argv
[1]);
143 return log_error_errno(r
, "Failed to look for machine %s: %m", argv
[1]);
151 path
= empty_or_dash_to_null(path
);
153 determine_compression_from_filename(path
);
156 open_fd
= open(path
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_CLOEXEC
|O_NOCTTY
, 0666);
158 return log_error_errno(errno
, "Failed to open raw image for export: %m");
162 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local
, path
, import_compress_type_to_string(arg_compress
));
164 _cleanup_free_
char *pretty
= NULL
;
168 (void) fd_get_path(fd
, &pretty
);
169 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local
, strna(pretty
), import_compress_type_to_string(arg_compress
));
172 r
= import_allocate_event_with_signals(&event
);
176 r
= raw_export_new(&export
, event
, on_raw_finished
, event
);
178 return log_error_errno(r
, "Failed to allocate exporter: %m");
180 r
= raw_export_start(export
, local
, fd
, arg_compress
);
182 return log_error_errno(r
, "Failed to export image: %m");
184 r
= sd_event_loop(event
);
186 return log_error_errno(r
, "Failed to run event loop: %m");
188 log_info("Exiting.");
192 static int help(int argc
, char *argv
[], void *userdata
) {
193 printf("%1$s [OPTIONS...] {COMMAND} ...\n"
194 "\n%4$sExport disk images.%5$s\n"
195 "\n%2$sCommands:%3$s\n"
196 " tar NAME [FILE] Export a TAR image\n"
197 " raw NAME [FILE] Export a RAW image\n"
198 "\n%2$sOptions:%3$s\n"
199 " -h --help Show this help\n"
200 " --version Show package version\n"
201 " --format=FORMAT Select format\n"
202 " --class=CLASS Select image class (machine, sysext, confext,\n"
204 program_invocation_short_name
,
213 static int parse_argv(int argc
, char *argv
[]) {
221 static const struct option options
[] = {
222 { "help", no_argument
, NULL
, 'h' },
223 { "version", no_argument
, NULL
, ARG_VERSION
},
224 { "format", required_argument
, NULL
, ARG_FORMAT
},
225 { "class", required_argument
, NULL
, ARG_CLASS
},
234 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
239 return help(0, NULL
, NULL
);
245 if (streq(optarg
, "uncompressed"))
246 arg_compress
= IMPORT_COMPRESS_UNCOMPRESSED
;
247 else if (streq(optarg
, "xz"))
248 arg_compress
= IMPORT_COMPRESS_XZ
;
249 else if (streq(optarg
, "gzip"))
250 arg_compress
= IMPORT_COMPRESS_GZIP
;
251 else if (streq(optarg
, "bzip2"))
252 arg_compress
= IMPORT_COMPRESS_BZIP2
;
254 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
255 "Unknown format: %s", optarg
);
259 arg_class
= image_class_from_string(optarg
);
261 return log_error_errno(arg_class
, "Failed to parse --class= argument: %s", optarg
);
269 assert_not_reached();
275 static int export_main(int argc
, char *argv
[]) {
276 static const Verb verbs
[] = {
277 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
278 { "tar", 2, 3, 0, export_tar
},
279 { "raw", 2, 3, 0, export_raw
},
283 return dispatch_verb(argc
, argv
, verbs
, NULL
);
286 static int run(int argc
, char *argv
[]) {
289 setlocale(LC_ALL
, "");
292 r
= parse_argv(argc
, argv
);
296 (void) ignore_signals(SIGPIPE
);
298 return export_main(argc
, argv
);
301 DEFINE_MAIN_FUNCTION(run
);