Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <getopt.h>
4 : : #include <locale.h>
5 : :
6 : : #include "sd-event.h"
7 : : #include "sd-id128.h"
8 : :
9 : : #include "alloc-util.h"
10 : : #include "fd-util.h"
11 : : #include "fs-util.h"
12 : : #include "hostname-util.h"
13 : : #include "import-raw.h"
14 : : #include "import-tar.h"
15 : : #include "import-util.h"
16 : : #include "machine-image.h"
17 : : #include "main-func.h"
18 : : #include "signal-util.h"
19 : : #include "string-util.h"
20 : : #include "verbs.h"
21 : :
22 : : static bool arg_force = false;
23 : : static bool arg_read_only = false;
24 : : static const char *arg_image_root = "/var/lib/machines";
25 : :
26 : 0 : static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
27 [ # # ]: 0 : log_notice("Transfer aborted.");
28 : 0 : sd_event_exit(sd_event_source_get_event(s), EINTR);
29 : 0 : return 0;
30 : : }
31 : :
32 : 0 : static void on_tar_finished(TarImport *import, int error, void *userdata) {
33 : 0 : sd_event *event = userdata;
34 [ # # ]: 0 : assert(import);
35 : :
36 [ # # ]: 0 : if (error == 0)
37 [ # # ]: 0 : log_info("Operation completed successfully.");
38 : :
39 : 0 : sd_event_exit(event, abs(error));
40 : 0 : }
41 : :
42 : 0 : static int import_tar(int argc, char *argv[], void *userdata) {
43 : 0 : _cleanup_(tar_import_unrefp) TarImport *import = NULL;
44 : 0 : _cleanup_(sd_event_unrefp) sd_event *event = NULL;
45 : 0 : const char *path = NULL, *local = NULL;
46 : 0 : _cleanup_free_ char *ll = NULL;
47 : 0 : _cleanup_close_ int open_fd = -1;
48 : : int r, fd;
49 : :
50 [ # # ]: 0 : if (argc >= 2)
51 : 0 : path = argv[1];
52 : 0 : path = empty_or_dash_to_null(path);
53 : :
54 [ # # ]: 0 : if (argc >= 3)
55 : 0 : local = argv[2];
56 [ # # ]: 0 : else if (path)
57 : 0 : local = basename(path);
58 : 0 : local = empty_or_dash_to_null(local);
59 : :
60 [ # # ]: 0 : if (local) {
61 : 0 : r = tar_strip_suffixes(local, &ll);
62 [ # # ]: 0 : if (r < 0)
63 : 0 : return log_oom();
64 : :
65 : 0 : local = ll;
66 : :
67 [ # # ]: 0 : if (!machine_name_is_valid(local)) {
68 [ # # ]: 0 : log_error("Local image name '%s' is not valid.", local);
69 : 0 : return -EINVAL;
70 : : }
71 : :
72 [ # # ]: 0 : if (!arg_force) {
73 : 0 : r = image_find(IMAGE_MACHINE, local, NULL);
74 [ # # ]: 0 : if (r < 0) {
75 [ # # ]: 0 : if (r != -ENOENT)
76 [ # # ]: 0 : return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
77 : : } else {
78 [ # # ]: 0 : log_error("Image '%s' already exists.", local);
79 : 0 : return -EEXIST;
80 : : }
81 : : }
82 : : } else
83 : 0 : local = "imported";
84 : :
85 [ # # ]: 0 : if (path) {
86 : 0 : open_fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
87 [ # # ]: 0 : if (open_fd < 0)
88 [ # # ]: 0 : return log_error_errno(errno, "Failed to open tar image to import: %m");
89 : :
90 : 0 : fd = open_fd;
91 : :
92 [ # # ]: 0 : log_info("Importing '%s', saving as '%s'.", path, local);
93 : : } else {
94 : 0 : _cleanup_free_ char *pretty = NULL;
95 : :
96 : 0 : fd = STDIN_FILENO;
97 : :
98 : 0 : (void) fd_get_path(fd, &pretty);
99 [ # # ]: 0 : log_info("Importing '%s', saving as '%s'.", strna(pretty), local);
100 : : }
101 : :
102 : 0 : r = sd_event_default(&event);
103 [ # # ]: 0 : if (r < 0)
104 [ # # ]: 0 : return log_error_errno(r, "Failed to allocate event loop: %m");
105 : :
106 [ # # ]: 0 : assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
107 : 0 : (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
108 : 0 : (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
109 : :
110 : 0 : r = tar_import_new(&import, event, arg_image_root, on_tar_finished, event);
111 [ # # ]: 0 : if (r < 0)
112 [ # # ]: 0 : return log_error_errno(r, "Failed to allocate importer: %m");
113 : :
114 : 0 : r = tar_import_start(import, fd, local, arg_force, arg_read_only);
115 [ # # ]: 0 : if (r < 0)
116 [ # # ]: 0 : return log_error_errno(r, "Failed to import image: %m");
117 : :
118 : 0 : r = sd_event_loop(event);
119 [ # # ]: 0 : if (r < 0)
120 [ # # ]: 0 : return log_error_errno(r, "Failed to run event loop: %m");
121 : :
122 [ # # ]: 0 : log_info("Exiting.");
123 : 0 : return -r;
124 : : }
125 : :
126 : 0 : static void on_raw_finished(RawImport *import, int error, void *userdata) {
127 : 0 : sd_event *event = userdata;
128 [ # # ]: 0 : assert(import);
129 : :
130 [ # # ]: 0 : if (error == 0)
131 [ # # ]: 0 : log_info("Operation completed successfully.");
132 : :
133 : 0 : sd_event_exit(event, abs(error));
134 : 0 : }
135 : :
136 : 0 : static int import_raw(int argc, char *argv[], void *userdata) {
137 : 0 : _cleanup_(raw_import_unrefp) RawImport *import = NULL;
138 : 0 : _cleanup_(sd_event_unrefp) sd_event *event = NULL;
139 : 0 : const char *path = NULL, *local = NULL;
140 : 0 : _cleanup_free_ char *ll = NULL;
141 : 0 : _cleanup_close_ int open_fd = -1;
142 : : int r, fd;
143 : :
144 [ # # ]: 0 : if (argc >= 2)
145 : 0 : path = argv[1];
146 : 0 : path = empty_or_dash_to_null(path);
147 : :
148 [ # # ]: 0 : if (argc >= 3)
149 : 0 : local = argv[2];
150 [ # # ]: 0 : else if (path)
151 : 0 : local = basename(path);
152 : 0 : local = empty_or_dash_to_null(local);
153 : :
154 [ # # ]: 0 : if (local) {
155 : 0 : r = raw_strip_suffixes(local, &ll);
156 [ # # ]: 0 : if (r < 0)
157 : 0 : return log_oom();
158 : :
159 : 0 : local = ll;
160 : :
161 [ # # ]: 0 : if (!machine_name_is_valid(local)) {
162 [ # # ]: 0 : log_error("Local image name '%s' is not valid.", local);
163 : 0 : return -EINVAL;
164 : : }
165 : :
166 [ # # ]: 0 : if (!arg_force) {
167 : 0 : r = image_find(IMAGE_MACHINE, local, NULL);
168 [ # # ]: 0 : if (r < 0) {
169 [ # # ]: 0 : if (r != -ENOENT)
170 [ # # ]: 0 : return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
171 : : } else {
172 [ # # ]: 0 : log_error("Image '%s' already exists.", local);
173 : 0 : return -EEXIST;
174 : : }
175 : : }
176 : : } else
177 : 0 : local = "imported";
178 : :
179 [ # # ]: 0 : if (path) {
180 : 0 : open_fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
181 [ # # ]: 0 : if (open_fd < 0)
182 [ # # ]: 0 : return log_error_errno(errno, "Failed to open raw image to import: %m");
183 : :
184 : 0 : fd = open_fd;
185 : :
186 [ # # ]: 0 : log_info("Importing '%s', saving as '%s'.", path, local);
187 : : } else {
188 : 0 : _cleanup_free_ char *pretty = NULL;
189 : :
190 : 0 : fd = STDIN_FILENO;
191 : :
192 : 0 : (void) fd_get_path(fd, &pretty);
193 [ # # ]: 0 : log_info("Importing '%s', saving as '%s'.", strempty(pretty), local);
194 : : }
195 : :
196 : 0 : r = sd_event_default(&event);
197 [ # # ]: 0 : if (r < 0)
198 [ # # ]: 0 : return log_error_errno(r, "Failed to allocate event loop: %m");
199 : :
200 [ # # ]: 0 : assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
201 : 0 : (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
202 : 0 : (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
203 : :
204 : 0 : r = raw_import_new(&import, event, arg_image_root, on_raw_finished, event);
205 [ # # ]: 0 : if (r < 0)
206 [ # # ]: 0 : return log_error_errno(r, "Failed to allocate importer: %m");
207 : :
208 : 0 : r = raw_import_start(import, fd, local, arg_force, arg_read_only);
209 [ # # ]: 0 : if (r < 0)
210 [ # # ]: 0 : return log_error_errno(r, "Failed to import image: %m");
211 : :
212 : 0 : r = sd_event_loop(event);
213 [ # # ]: 0 : if (r < 0)
214 [ # # ]: 0 : return log_error_errno(r, "Failed to run event loop: %m");
215 : :
216 [ # # ]: 0 : log_info("Exiting.");
217 : 0 : return -r;
218 : : }
219 : :
220 : 12 : static int help(int argc, char *argv[], void *userdata) {
221 : :
222 : 12 : printf("%s [OPTIONS...] {COMMAND} ...\n\n"
223 : : "Import container or virtual machine images.\n\n"
224 : : " -h --help Show this help\n"
225 : : " --version Show package version\n"
226 : : " --force Force creation of image\n"
227 : : " --image-root=PATH Image root directory\n"
228 : : " --read-only Create a read-only image\n\n"
229 : : "Commands:\n"
230 : : " tar FILE [NAME] Import a TAR image\n"
231 : : " raw FILE [NAME] Import a RAW image\n",
232 : : program_invocation_short_name);
233 : :
234 : 12 : return 0;
235 : : }
236 : :
237 : 16 : static int parse_argv(int argc, char *argv[]) {
238 : :
239 : : enum {
240 : : ARG_VERSION = 0x100,
241 : : ARG_FORCE,
242 : : ARG_IMAGE_ROOT,
243 : : ARG_READ_ONLY,
244 : : };
245 : :
246 : : static const struct option options[] = {
247 : : { "help", no_argument, NULL, 'h' },
248 : : { "version", no_argument, NULL, ARG_VERSION },
249 : : { "force", no_argument, NULL, ARG_FORCE },
250 : : { "image-root", required_argument, NULL, ARG_IMAGE_ROOT },
251 : : { "read-only", no_argument, NULL, ARG_READ_ONLY },
252 : : {}
253 : : };
254 : :
255 : : int c;
256 : :
257 [ - + ]: 16 : assert(argc >= 0);
258 [ - + ]: 16 : assert(argv);
259 : :
260 [ + - ]: 16 : while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
261 : :
262 [ + - - - : 16 : switch (c) {
- + - ]
263 : :
264 : 12 : case 'h':
265 : 12 : return help(0, NULL, NULL);
266 : :
267 : 0 : case ARG_VERSION:
268 : 0 : return version();
269 : :
270 : 0 : case ARG_FORCE:
271 : 0 : arg_force = true;
272 : 0 : break;
273 : :
274 : 0 : case ARG_IMAGE_ROOT:
275 : 0 : arg_image_root = optarg;
276 : 0 : break;
277 : :
278 : 0 : case ARG_READ_ONLY:
279 : 0 : arg_read_only = true;
280 : 0 : break;
281 : :
282 : 4 : case '?':
283 : 4 : return -EINVAL;
284 : :
285 : 0 : default:
286 : 0 : assert_not_reached("Unhandled option");
287 : : }
288 : :
289 : 0 : return 1;
290 : : }
291 : :
292 : 0 : static int import_main(int argc, char *argv[]) {
293 : : static const Verb verbs[] = {
294 : : { "help", VERB_ANY, VERB_ANY, 0, help },
295 : : { "tar", 2, 3, 0, import_tar },
296 : : { "raw", 2, 3, 0, import_raw },
297 : : {}
298 : : };
299 : :
300 : 0 : return dispatch_verb(argc, argv, verbs, NULL);
301 : : }
302 : :
303 : 16 : static int run(int argc, char *argv[]) {
304 : : int r;
305 : :
306 : 16 : setlocale(LC_ALL, "");
307 : 16 : log_parse_environment();
308 : 16 : log_open();
309 : :
310 : 16 : r = parse_argv(argc, argv);
311 [ + - ]: 16 : if (r <= 0)
312 : 16 : return 0;
313 : :
314 : 0 : (void) ignore_signals(SIGPIPE, -1);
315 : :
316 : 0 : return import_main(argc, argv);
317 : : }
318 : :
319 : 16 : DEFINE_MAIN_FUNCTION(run);
|