]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/import/export.c
importd: validate local image names with the right helper
[thirdparty/systemd.git] / src / import / export.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
587fec42
LP
2
3#include <getopt.h>
ca78ad1d 4#include <locale.h>
587fec42
LP
5
6#include "sd-event.h"
dccca82b 7#include "sd-id128.h"
3f6fd1ba 8
b5efdb8a 9#include "alloc-util.h"
d6b4d1c7 10#include "build.h"
57f1b61b 11#include "discover-image.h"
3f6fd1ba
LP
12#include "export-raw.h"
13#include "export-tar.h"
3ffd4af2 14#include "fd-util.h"
f4f15635 15#include "fs-util.h"
25300b5a 16#include "hostname-util.h"
423bba99 17#include "import-common.h"
587fec42 18#include "import-util.h"
5e332028 19#include "main-func.h"
3f6fd1ba 20#include "signal-util.h"
07630cea 21#include "string-util.h"
4f9791a3 22#include "terminal-util.h"
3f6fd1ba 23#include "verbs.h"
587fec42
LP
24
25static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN;
7af5785d 26static ImageClass arg_class = IMAGE_MACHINE;
587fec42
LP
27
28static void determine_compression_from_filename(const char *p) {
29
30 if (arg_compress != IMPORT_COMPRESS_UNKNOWN)
31 return;
32
33 if (!p) {
34 arg_compress = IMPORT_COMPRESS_UNCOMPRESSED;
35 return;
36 }
37
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;
44 else
45 arg_compress = IMPORT_COMPRESS_UNCOMPRESSED;
46}
47
587fec42
LP
48static void on_tar_finished(TarExport *export, int error, void *userdata) {
49 sd_event *event = userdata;
50 assert(export);
51
52 if (error == 0)
53 log_info("Operation completed successfully.");
54
55 sd_event_exit(event, abs(error));
56}
57
58static int export_tar(int argc, char *argv[], void *userdata) {
59 _cleanup_(tar_export_unrefp) TarExport *export = NULL;
4afd3348 60 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
587fec42
LP
61 _cleanup_(image_unrefp) Image *image = NULL;
62 const char *path = NULL, *local = NULL;
254d1313 63 _cleanup_close_ int open_fd = -EBADF;
587fec42
LP
64 int r, fd;
65
8f20b498
LP
66 local = argv[1];
67 if (image_name_is_valid(local)) {
68 r = image_find(arg_class, local, NULL, &image);
3a6ce860 69 if (r == -ENOENT)
8f20b498 70 return log_error_errno(r, "Image %s not found.", local);
587fec42 71 if (r < 0)
8f20b498 72 return log_error_errno(r, "Failed to look for image %s: %m", local);
587fec42
LP
73
74 local = image->path;
75 } else
76 local = argv[1];
77
78 if (argc >= 3)
79 path = argv[2];
dc90e0fa 80 path = empty_or_dash_to_null(path);
587fec42
LP
81
82 determine_compression_from_filename(path);
83
84 if (path) {
85 open_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
86 if (open_fd < 0)
87 return log_error_errno(errno, "Failed to open tar image for export: %m");
88
89 fd = open_fd;
90
91 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, path, import_compress_type_to_string(arg_compress));
92 } else {
93 _cleanup_free_ char *pretty = NULL;
94
95 fd = STDOUT_FILENO;
96
1295c906 97 (void) fd_get_path(fd, &pretty);
587fec42
LP
98 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, strna(pretty), import_compress_type_to_string(arg_compress));
99 }
100
423bba99 101 r = import_allocate_event_with_signals(&event);
587fec42 102 if (r < 0)
423bba99 103 return r;
587fec42
LP
104
105 r = tar_export_new(&export, event, on_tar_finished, event);
106 if (r < 0)
107 return log_error_errno(r, "Failed to allocate exporter: %m");
108
109 r = tar_export_start(export, local, fd, arg_compress);
110 if (r < 0)
111 return log_error_errno(r, "Failed to export image: %m");
112
113 r = sd_event_loop(event);
114 if (r < 0)
115 return log_error_errno(r, "Failed to run event loop: %m");
116
117 log_info("Exiting.");
118 return -r;
119}
120
121static void on_raw_finished(RawExport *export, int error, void *userdata) {
122 sd_event *event = userdata;
123 assert(export);
124
125 if (error == 0)
126 log_info("Operation completed successfully.");
127
128 sd_event_exit(event, abs(error));
129}
130
131static int export_raw(int argc, char *argv[], void *userdata) {
132 _cleanup_(raw_export_unrefp) RawExport *export = NULL;
4afd3348 133 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
587fec42
LP
134 _cleanup_(image_unrefp) Image *image = NULL;
135 const char *path = NULL, *local = NULL;
254d1313 136 _cleanup_close_ int open_fd = -EBADF;
587fec42
LP
137 int r, fd;
138
8f20b498
LP
139 local = argv[1];
140 if (image_name_is_valid(local)) {
141 r = image_find(arg_class, local, NULL, &image);
3a6ce860 142 if (r == -ENOENT)
8f20b498 143 return log_error_errno(r, "Image %s not found.", local);
587fec42 144 if (r < 0)
8f20b498 145 return log_error_errno(r, "Failed to look for image %s: %m", local);
587fec42
LP
146
147 local = image->path;
148 } else
149 local = argv[1];
150
151 if (argc >= 3)
152 path = argv[2];
dc90e0fa 153 path = empty_or_dash_to_null(path);
587fec42
LP
154
155 determine_compression_from_filename(path);
156
157 if (path) {
158 open_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
159 if (open_fd < 0)
160 return log_error_errno(errno, "Failed to open raw image for export: %m");
161
162 fd = open_fd;
163
164 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, path, import_compress_type_to_string(arg_compress));
165 } else {
166 _cleanup_free_ char *pretty = NULL;
167
168 fd = STDOUT_FILENO;
169
1295c906 170 (void) fd_get_path(fd, &pretty);
587fec42
LP
171 log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, strna(pretty), import_compress_type_to_string(arg_compress));
172 }
173
423bba99 174 r = import_allocate_event_with_signals(&event);
587fec42 175 if (r < 0)
423bba99 176 return r;
587fec42
LP
177
178 r = raw_export_new(&export, event, on_raw_finished, event);
179 if (r < 0)
180 return log_error_errno(r, "Failed to allocate exporter: %m");
181
182 r = raw_export_start(export, local, fd, arg_compress);
183 if (r < 0)
184 return log_error_errno(r, "Failed to export image: %m");
185
186 r = sd_event_loop(event);
187 if (r < 0)
188 return log_error_errno(r, "Failed to run event loop: %m");
189
190 log_info("Exiting.");
191 return -r;
192}
193
194static int help(int argc, char *argv[], void *userdata) {
4f9791a3 195 printf("%1$s [OPTIONS...] {COMMAND} ...\n"
7af5785d 196 "\n%4$sExport disk images.%5$s\n"
4f9791a3
ZJS
197 "\n%2$sCommands:%3$s\n"
198 " tar NAME [FILE] Export a TAR image\n"
199 " raw NAME [FILE] Export a RAW image\n"
200 "\n%2$sOptions:%3$s\n"
587fec42
LP
201 " -h --help Show this help\n"
202 " --version Show package version\n"
7af5785d
LP
203 " --format=FORMAT Select format\n"
204 " --class=CLASS Select image class (machine, sysext, confext,\n"
205 " portable)\n",
4f9791a3
ZJS
206 program_invocation_short_name,
207 ansi_underline(),
208 ansi_normal(),
209 ansi_highlight(),
210 ansi_normal());
587fec42
LP
211
212 return 0;
213}
214
215static int parse_argv(int argc, char *argv[]) {
216
217 enum {
218 ARG_VERSION = 0x100,
219 ARG_FORMAT,
7af5785d 220 ARG_CLASS,
587fec42
LP
221 };
222
223 static const struct option options[] = {
224 { "help", no_argument, NULL, 'h' },
225 { "version", no_argument, NULL, ARG_VERSION },
226 { "format", required_argument, NULL, ARG_FORMAT },
7af5785d 227 { "class", required_argument, NULL, ARG_CLASS },
587fec42
LP
228 {}
229 };
230
231 int c;
232
233 assert(argc >= 0);
234 assert(argv);
235
236 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
237
238 switch (c) {
239
240 case 'h':
241 return help(0, NULL, NULL);
242
243 case ARG_VERSION:
3f6fd1ba 244 return version();
587fec42
LP
245
246 case ARG_FORMAT:
247 if (streq(optarg, "uncompressed"))
248 arg_compress = IMPORT_COMPRESS_UNCOMPRESSED;
249 else if (streq(optarg, "xz"))
250 arg_compress = IMPORT_COMPRESS_XZ;
251 else if (streq(optarg, "gzip"))
252 arg_compress = IMPORT_COMPRESS_GZIP;
253 else if (streq(optarg, "bzip2"))
254 arg_compress = IMPORT_COMPRESS_BZIP2;
baaa35ad
ZJS
255 else
256 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
257 "Unknown format: %s", optarg);
587fec42
LP
258 break;
259
7af5785d
LP
260 case ARG_CLASS:
261 arg_class = image_class_from_string(optarg);
262 if (arg_class < 0)
263 return log_error_errno(arg_class, "Failed to parse --class= argument: %s", optarg);
264
265 break;
266
587fec42
LP
267 case '?':
268 return -EINVAL;
269
270 default:
04499a70 271 assert_not_reached();
587fec42
LP
272 }
273
274 return 1;
275}
276
277static int export_main(int argc, char *argv[]) {
587fec42
LP
278 static const Verb verbs[] = {
279 { "help", VERB_ANY, VERB_ANY, 0, help },
280 { "tar", 2, 3, 0, export_tar },
281 { "raw", 2, 3, 0, export_raw },
282 {}
283 };
284
285 return dispatch_verb(argc, argv, verbs, NULL);
286}
287
5272ae42 288static int run(int argc, char *argv[]) {
587fec42
LP
289 int r;
290
291 setlocale(LC_ALL, "");
b37ec1e7 292 log_setup();
587fec42
LP
293
294 r = parse_argv(argc, argv);
295 if (r <= 0)
5272ae42 296 return r;
587fec42 297
9c274488 298 (void) ignore_signals(SIGPIPE);
587fec42 299
5272ae42 300 return export_main(argc, argv);
587fec42 301}
5272ae42
ZJS
302
303DEFINE_MAIN_FUNCTION(run);