]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/import/import.c
calendarspec: rename free_chain() to chain_free()
[thirdparty/systemd.git] / src / import / import.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
b6e676ce
LP
2
3#include <getopt.h>
ca78ad1d 4#include <locale.h>
b6e676ce
LP
5
6#include "sd-event.h"
dccca82b 7#include "sd-id128.h"
3f6fd1ba 8
b5efdb8a 9#include "alloc-util.h"
3ffd4af2 10#include "fd-util.h"
f4f15635 11#include "fs-util.h"
25300b5a 12#include "hostname-util.h"
b6e676ce 13#include "import-raw.h"
3f6fd1ba
LP
14#include "import-tar.h"
15#include "import-util.h"
16#include "machine-image.h"
5e332028 17#include "main-func.h"
3f6fd1ba 18#include "signal-util.h"
07630cea 19#include "string-util.h"
3f6fd1ba 20#include "verbs.h"
b6e676ce
LP
21
22static bool arg_force = false;
23static bool arg_read_only = false;
24static const char *arg_image_root = "/var/lib/machines";
25
26static 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
32static 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
42static int import_tar(int argc, char *argv[], void *userdata) {
43 _cleanup_(tar_import_unrefp) TarImport *import = NULL;
4afd3348 44 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
b6e676ce
LP
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) {
5ef46e5f 75 r = image_find(IMAGE_MACHINE, local, NULL);
3a6ce860
LP
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 {
92dfd88b 80 log_error("Image '%s' already exists.", local);
b6e676ce
LP
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
1295c906 100 (void) fd_get_path(fd, &pretty);
b6e676ce
LP
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
72c0a2c2
LP
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);
b6e676ce
LP
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
128static 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
138static int import_raw(int argc, char *argv[], void *userdata) {
139 _cleanup_(raw_import_unrefp) RawImport *import = NULL;
4afd3348 140 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
b6e676ce
LP
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) {
5ef46e5f 171 r = image_find(IMAGE_MACHINE, local, NULL);
3a6ce860
LP
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 {
92dfd88b 176 log_error("Image '%s' already exists.", local);
b6e676ce
LP
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
1295c906 196 (void) fd_get_path(fd, &pretty);
fe4377fa 197 log_info("Importing '%s', saving as '%s'.", strempty(pretty), local);
b6e676ce
LP
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
72c0a2c2
LP
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);
b6e676ce
LP
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
224static int help(int argc, char *argv[], void *userdata) {
225
226 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
587fec42 227 "Import container or virtual machine images.\n\n"
b6e676ce
LP
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"
587fec42
LP
234 " tar FILE [NAME] Import a TAR image\n"
235 " raw FILE [NAME] Import a RAW image\n",
b6e676ce
LP
236 program_invocation_short_name);
237
238 return 0;
239}
240
241static 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:
3f6fd1ba 272 return version();
b6e676ce
LP
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
296static int import_main(int argc, char *argv[]) {
b6e676ce
LP
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
5272ae42 307static int run(int argc, char *argv[]) {
b6e676ce
LP
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)
5272ae42 316 return 0;
b6e676ce 317
ce30c8dc 318 (void) ignore_signals(SIGPIPE, -1);
b6e676ce 319
5272ae42 320 return import_main(argc, argv);
b6e676ce 321}
5272ae42
ZJS
322
323DEFINE_MAIN_FUNCTION(run);