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