]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
3d7415f4 LP |
2 | |
3 | #include <sys/prctl.h> | |
d7e454ba | 4 | #include <sys/wait.h> |
3d7415f4 LP |
5 | |
6 | #include "sd-bus.h" | |
3ffd4af2 | 7 | |
b5efdb8a | 8 | #include "alloc-util.h" |
a0afd4e7 | 9 | #include "build-path.h" |
3d7415f4 | 10 | #include "bus-common-errors.h" |
40af3d02 | 11 | #include "bus-get-properties.h" |
ac9f55ed | 12 | #include "bus-log-control-api.h" |
269e4d2d | 13 | #include "bus-polkit.h" |
82fa9f28 | 14 | #include "common-signal.h" |
28db6fbf | 15 | #include "constants.h" |
deb86997 | 16 | #include "daemon-util.h" |
7af5785d | 17 | #include "discover-image.h" |
d7548908 | 18 | #include "env-util.h" |
09232207 | 19 | #include "event-util.h" |
3ffd4af2 | 20 | #include "fd-util.h" |
1d7579c4 | 21 | #include "float.h" |
3ffd4af2 | 22 | #include "hostname-util.h" |
7af5785d | 23 | #include "import-common.h" |
3ffd4af2 | 24 | #include "import-util.h" |
432cea00 | 25 | #include "machine-pool.h" |
5e332028 | 26 | #include "main-func.h" |
f5947a5e | 27 | #include "missing_capability.h" |
35cd0ba5 | 28 | #include "mkdir-label.h" |
7af5785d | 29 | #include "os-util.h" |
6bedfcbb | 30 | #include "parse-util.h" |
113b3fc1 | 31 | #include "path-util.h" |
ed5033fd | 32 | #include "percent-util.h" |
0b452006 | 33 | #include "process-util.h" |
fc021a5b | 34 | #include "service-util.h" |
40af3d02 | 35 | #include "signal-util.h" |
3ffd4af2 | 36 | #include "socket-util.h" |
176a05c2 | 37 | #include "stat-util.h" |
8b43440b | 38 | #include "string-table.h" |
3ffd4af2 | 39 | #include "strv.h" |
7ccbd1ae | 40 | #include "syslog-util.h" |
ee104e11 | 41 | #include "user-util.h" |
49cf4170 | 42 | #include "web-util.h" |
3d7415f4 LP |
43 | |
44 | typedef struct Transfer Transfer; | |
45 | typedef struct Manager Manager; | |
46 | ||
47 | typedef enum TransferType { | |
b6e676ce LP |
48 | TRANSFER_IMPORT_TAR, |
49 | TRANSFER_IMPORT_RAW, | |
1d7579c4 | 50 | TRANSFER_IMPORT_FS, |
587fec42 LP |
51 | TRANSFER_EXPORT_TAR, |
52 | TRANSFER_EXPORT_RAW, | |
b6e676ce LP |
53 | TRANSFER_PULL_TAR, |
54 | TRANSFER_PULL_RAW, | |
3d7415f4 | 55 | _TRANSFER_TYPE_MAX, |
2d93c20e | 56 | _TRANSFER_TYPE_INVALID = -EINVAL, |
3d7415f4 LP |
57 | } TransferType; |
58 | ||
59 | struct Transfer { | |
60 | Manager *manager; | |
61 | ||
62 | uint32_t id; | |
63 | char *object_path; | |
64 | ||
65 | TransferType type; | |
66 | ImportVerify verify; | |
67 | ||
68 | char *remote; | |
69 | char *local; | |
7af5785d LP |
70 | ImageClass class; |
71 | ImportFlags flags; | |
587fec42 | 72 | char *format; |
3d7415f4 | 73 | |
09232207 | 74 | PidRef pidref; |
3d7415f4 LP |
75 | |
76 | int log_fd; | |
77 | ||
78 | char log_message[LINE_MAX]; | |
79 | size_t log_message_size; | |
80 | ||
81 | sd_event_source *pid_event_source; | |
82 | sd_event_source *log_event_source; | |
83 | ||
84 | unsigned n_canceled; | |
7079cfef | 85 | unsigned progress_percent; |
71cb203a | 86 | unsigned progress_percent_sent; |
b6e676ce LP |
87 | |
88 | int stdin_fd; | |
587fec42 | 89 | int stdout_fd; |
3d7415f4 LP |
90 | }; |
91 | ||
92 | struct Manager { | |
93 | sd_event *event; | |
94 | sd_bus *bus; | |
95 | ||
96 | uint32_t current_transfer_id; | |
97 | Hashmap *transfers; | |
98 | ||
99 | Hashmap *polkit_registry; | |
7079cfef LP |
100 | |
101 | int notify_fd; | |
102 | ||
103 | sd_event_source *notify_event_source; | |
c7779a61 IS |
104 | |
105 | bool use_btrfs_subvol; | |
106 | bool use_btrfs_quota; | |
3d7415f4 LP |
107 | }; |
108 | ||
109 | #define TRANSFERS_MAX 64 | |
110 | ||
111 | static const char* const transfer_type_table[_TRANSFER_TYPE_MAX] = { | |
b6e676ce LP |
112 | [TRANSFER_IMPORT_TAR] = "import-tar", |
113 | [TRANSFER_IMPORT_RAW] = "import-raw", | |
b37ec1e7 | 114 | [TRANSFER_IMPORT_FS] = "import-fs", |
587fec42 LP |
115 | [TRANSFER_EXPORT_TAR] = "export-tar", |
116 | [TRANSFER_EXPORT_RAW] = "export-raw", | |
b37ec1e7 LP |
117 | [TRANSFER_PULL_TAR] = "pull-tar", |
118 | [TRANSFER_PULL_RAW] = "pull-raw", | |
3d7415f4 LP |
119 | }; |
120 | ||
b9a5f858 | 121 | DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(transfer_type, TransferType); |
3d7415f4 LP |
122 | |
123 | static Transfer *transfer_unref(Transfer *t) { | |
124 | if (!t) | |
125 | return NULL; | |
126 | ||
127 | if (t->manager) | |
128 | hashmap_remove(t->manager->transfers, UINT32_TO_PTR(t->id)); | |
129 | ||
130 | sd_event_source_unref(t->pid_event_source); | |
131 | sd_event_source_unref(t->log_event_source); | |
132 | ||
133 | free(t->remote); | |
134 | free(t->local); | |
587fec42 | 135 | free(t->format); |
3d7415f4 LP |
136 | free(t->object_path); |
137 | ||
09232207 | 138 | pidref_done_sigkill_wait(&t->pidref); |
3d7415f4 LP |
139 | |
140 | safe_close(t->log_fd); | |
b6e676ce | 141 | safe_close(t->stdin_fd); |
587fec42 | 142 | safe_close(t->stdout_fd); |
3d7415f4 | 143 | |
6b430fdb | 144 | return mfree(t); |
3d7415f4 LP |
145 | } |
146 | ||
147 | DEFINE_TRIVIAL_CLEANUP_FUNC(Transfer*, transfer_unref); | |
148 | ||
149 | static int transfer_new(Manager *m, Transfer **ret) { | |
150 | _cleanup_(transfer_unrefp) Transfer *t = NULL; | |
151 | uint32_t id; | |
152 | int r; | |
153 | ||
154 | assert(m); | |
155 | assert(ret); | |
156 | ||
157 | if (hashmap_size(m->transfers) >= TRANSFERS_MAX) | |
158 | return -E2BIG; | |
159 | ||
0d94088e | 160 | t = new(Transfer, 1); |
3d7415f4 LP |
161 | if (!t) |
162 | return -ENOMEM; | |
163 | ||
0d94088e YW |
164 | *t = (Transfer) { |
165 | .type = _TRANSFER_TYPE_INVALID, | |
254d1313 ZJS |
166 | .log_fd = -EBADF, |
167 | .stdin_fd = -EBADF, | |
168 | .stdout_fd = -EBADF, | |
0d94088e | 169 | .verify = _IMPORT_VERIFY_INVALID, |
71cb203a LP |
170 | .progress_percent = UINT_MAX, |
171 | .progress_percent_sent = UINT_MAX, | |
0d94088e | 172 | }; |
3d7415f4 LP |
173 | |
174 | id = m->current_transfer_id + 1; | |
175 | ||
176 | if (asprintf(&t->object_path, "/org/freedesktop/import1/transfer/_%" PRIu32, id) < 0) | |
177 | return -ENOMEM; | |
178 | ||
df24a407 | 179 | r = hashmap_ensure_put(&m->transfers, &trivial_hash_ops, UINT32_TO_PTR(id), t); |
3d7415f4 LP |
180 | if (r < 0) |
181 | return r; | |
182 | ||
183 | m->current_transfer_id = id; | |
184 | ||
185 | t->manager = m; | |
186 | t->id = id; | |
187 | ||
1cc6c93a | 188 | *ret = TAKE_PTR(t); |
3d7415f4 LP |
189 | |
190 | return 0; | |
191 | } | |
192 | ||
1d7579c4 LP |
193 | static double transfer_percent_as_double(Transfer *t) { |
194 | assert(t); | |
195 | ||
f5fbe71d | 196 | if (t->progress_percent == UINT_MAX) |
1d7579c4 LP |
197 | return -DBL_MAX; |
198 | ||
199 | return (double) t->progress_percent / 100.0; | |
200 | } | |
201 | ||
3d7415f4 LP |
202 | static void transfer_send_log_line(Transfer *t, const char *line) { |
203 | int r, priority = LOG_INFO; | |
204 | ||
205 | assert(t); | |
206 | assert(line); | |
207 | ||
208 | syslog_parse_priority(&line, &priority, true); | |
209 | ||
09d46cfd | 210 | log_full(priority, "(transfer%" PRIu32 ") %s", t->id, line); |
3d7415f4 LP |
211 | |
212 | r = sd_bus_emit_signal( | |
213 | t->manager->bus, | |
214 | t->object_path, | |
215 | "org.freedesktop.import1.Transfer", | |
216 | "LogMessage", | |
217 | "us", | |
218 | priority, | |
219 | line); | |
220 | if (r < 0) | |
5b6299ee | 221 | log_warning_errno(r, "Cannot emit log message signal, ignoring: %m"); |
71cb203a LP |
222 | } |
223 | ||
224 | static void transfer_send_progress_update(Transfer *t) { | |
225 | int r; | |
226 | ||
227 | assert(t); | |
228 | ||
229 | if (t->progress_percent_sent == t->progress_percent) | |
230 | return; | |
231 | ||
232 | r = sd_bus_emit_signal( | |
233 | t->manager->bus, | |
234 | t->object_path, | |
235 | "org.freedesktop.import1.Transfer", | |
236 | "ProgressUpdate", | |
237 | "d", | |
238 | transfer_percent_as_double(t)); | |
239 | if (r < 0) | |
240 | log_warning_errno(r, "Cannot emit progress update signal, ignoring: %m"); | |
241 | ||
242 | t->progress_percent_sent = t->progress_percent; | |
243 | } | |
3d7415f4 LP |
244 | |
245 | static void transfer_send_logs(Transfer *t, bool flush) { | |
246 | assert(t); | |
247 | ||
248 | /* Try to send out all log messages, if we can. But if we | |
249 | * can't we remove the messages from the buffer, but don't | |
250 | * fail */ | |
251 | ||
252 | while (t->log_message_size > 0) { | |
253 | _cleanup_free_ char *n = NULL; | |
254 | char *e; | |
255 | ||
256 | if (t->log_message_size >= sizeof(t->log_message)) | |
257 | e = t->log_message + sizeof(t->log_message); | |
258 | else { | |
259 | char *a, *b; | |
260 | ||
261 | a = memchr(t->log_message, 0, t->log_message_size); | |
262 | b = memchr(t->log_message, '\n', t->log_message_size); | |
263 | ||
264 | if (a && b) | |
265 | e = a < b ? a : b; | |
266 | else if (a) | |
267 | e = a; | |
268 | else | |
269 | e = b; | |
270 | } | |
271 | ||
272 | if (!e) { | |
273 | if (!flush) | |
274 | return; | |
275 | ||
276 | e = t->log_message + t->log_message_size; | |
277 | } | |
278 | ||
279 | n = strndup(t->log_message, e - t->log_message); | |
280 | ||
281 | /* Skip over NUL and newlines */ | |
ed0cb346 | 282 | while (e < t->log_message + t->log_message_size && IN_SET(*e, 0, '\n')) |
3d7415f4 LP |
283 | e++; |
284 | ||
285 | memmove(t->log_message, e, t->log_message + sizeof(t->log_message) - e); | |
286 | t->log_message_size -= e - t->log_message; | |
287 | ||
288 | if (!n) { | |
289 | log_oom(); | |
290 | continue; | |
291 | } | |
292 | ||
293 | if (isempty(n)) | |
294 | continue; | |
295 | ||
296 | transfer_send_log_line(t, n); | |
297 | } | |
298 | } | |
299 | ||
300 | static int transfer_finalize(Transfer *t, bool success) { | |
301 | int r; | |
302 | ||
303 | assert(t); | |
304 | ||
305 | transfer_send_logs(t, true); | |
306 | ||
307 | r = sd_bus_emit_signal( | |
308 | t->manager->bus, | |
309 | "/org/freedesktop/import1", | |
310 | "org.freedesktop.import1.Manager", | |
311 | "TransferRemoved", | |
312 | "uos", | |
313 | t->id, | |
314 | t->object_path, | |
315 | success ? "done" : | |
316 | t->n_canceled > 0 ? "canceled" : "failed"); | |
317 | ||
318 | if (r < 0) | |
319 | log_error_errno(r, "Cannot emit message: %m"); | |
320 | ||
321 | transfer_unref(t); | |
322 | return 0; | |
323 | } | |
324 | ||
325 | static int transfer_cancel(Transfer *t) { | |
326 | int r; | |
327 | ||
328 | assert(t); | |
329 | ||
09232207 | 330 | r = pidref_kill_and_sigcont(&t->pidref, t->n_canceled < 3 ? SIGTERM : SIGKILL); |
3d7415f4 LP |
331 | if (r < 0) |
332 | return r; | |
333 | ||
334 | t->n_canceled++; | |
335 | return 0; | |
336 | } | |
337 | ||
338 | static int transfer_on_pid(sd_event_source *s, const siginfo_t *si, void *userdata) { | |
99534007 | 339 | Transfer *t = ASSERT_PTR(userdata); |
3d7415f4 LP |
340 | bool success = false; |
341 | ||
342 | assert(s); | |
3d7415f4 LP |
343 | |
344 | if (si->si_code == CLD_EXITED) { | |
345 | if (si->si_status != 0) | |
4b71c27b | 346 | log_error("Transfer process failed with exit code %i.", si->si_status); |
3d7415f4 | 347 | else { |
4b71c27b | 348 | log_debug("Transfer process succeeded."); |
3d7415f4 LP |
349 | success = true; |
350 | } | |
351 | ||
3742095b | 352 | } else if (IN_SET(si->si_code, CLD_KILLED, CLD_DUMPED)) |
4b71c27b | 353 | log_error("Transfer process terminated by signal %s.", signal_to_string(si->si_status)); |
3d7415f4 | 354 | else |
4b71c27b | 355 | log_error("Transfer process failed due to unknown reason."); |
3d7415f4 | 356 | |
09232207 | 357 | pidref_done(&t->pidref); |
3d7415f4 LP |
358 | |
359 | return transfer_finalize(t, success); | |
360 | } | |
361 | ||
362 | static int transfer_on_log(sd_event_source *s, int fd, uint32_t revents, void *userdata) { | |
99534007 | 363 | Transfer *t = ASSERT_PTR(userdata); |
3d7415f4 LP |
364 | ssize_t l; |
365 | ||
366 | assert(s); | |
3d7415f4 LP |
367 | |
368 | l = read(fd, t->log_message + t->log_message_size, sizeof(t->log_message) - t->log_message_size); | |
b0325c99 LP |
369 | if (l < 0) |
370 | log_error_errno(errno, "Failed to read log message: %m"); | |
3d7415f4 LP |
371 | if (l <= 0) { |
372 | /* EOF/read error. We just close the pipe here, and | |
373 | * close the watch, waiting for the SIGCHLD to arrive, | |
374 | * before we do anything else. */ | |
3d7415f4 LP |
375 | t->log_event_source = sd_event_source_unref(t->log_event_source); |
376 | return 0; | |
377 | } | |
378 | ||
379 | t->log_message_size += l; | |
380 | ||
381 | transfer_send_logs(t, false); | |
382 | ||
383 | return 0; | |
384 | } | |
385 | ||
386 | static int transfer_start(Transfer *t) { | |
71136404 | 387 | _cleanup_close_pair_ int pipefd[2] = EBADF_PAIR; |
3d7415f4 LP |
388 | int r; |
389 | ||
390 | assert(t); | |
09232207 | 391 | assert(!pidref_is_set(&t->pidref)); |
3d7415f4 LP |
392 | |
393 | if (pipe2(pipefd, O_CLOEXEC) < 0) | |
394 | return -errno; | |
395 | ||
09232207 LP |
396 | r = pidref_safe_fork_full( |
397 | "(sd-transfer)", | |
398 | (int[]) { t->stdin_fd, t->stdout_fd < 0 ? pipefd[1] : t->stdout_fd, pipefd[1] }, | |
399 | /* except_fds= */ NULL, /* n_except_fds= */ 0, | |
1a176d5b | 400 | FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_REOPEN_LOG, |
09232207 | 401 | &t->pidref); |
4c253ed1 LP |
402 | if (r < 0) |
403 | return r; | |
404 | if (r == 0) { | |
3d7415f4 | 405 | const char *cmd[] = { |
1d7579c4 | 406 | NULL, /* systemd-import, systemd-import-fs, systemd-export or systemd-pull */ |
b43d75c3 | 407 | NULL, /* tar, raw */ |
b6e676ce | 408 | NULL, /* --verify= */ |
3d7415f4 | 409 | NULL, /* verify argument */ |
7af5785d LP |
410 | NULL, /* --class= */ |
411 | NULL, /* class argument */ | |
b146afc4 | 412 | NULL, /* --keep-download= */ |
3d7415f4 | 413 | NULL, /* maybe --force */ |
b6e676ce | 414 | NULL, /* maybe --read-only */ |
587fec42 LP |
415 | NULL, /* if so: the actual URL */ |
416 | NULL, /* maybe --format= */ | |
417 | NULL, /* if so: the actual format */ | |
3d7415f4 LP |
418 | NULL, /* remote */ |
419 | NULL, /* local */ | |
420 | NULL | |
421 | }; | |
b37ec1e7 | 422 | size_t k = 0; |
3d7415f4 LP |
423 | |
424 | /* Child */ | |
425 | ||
df8067ef ZJS |
426 | if (setenv("SYSTEMD_LOG_TARGET", "console-prefixed", 1) < 0 || |
427 | setenv("NOTIFY_SOCKET", "/run/systemd/import/notify", 1) < 0) { | |
428 | log_error_errno(errno, "setenv() failed: %m"); | |
429 | _exit(EXIT_FAILURE); | |
430 | } | |
3d7415f4 | 431 | |
5a985dd0 LP |
432 | r = setenv_systemd_log_level(); |
433 | if (r < 0) | |
434 | log_warning_errno(r, "Failed to update $SYSTEMD_LOG_LEVEL, ignoring: %m"); | |
435 | ||
d7548908 YW |
436 | r = setenv_systemd_exec_pid(true); |
437 | if (r < 0) | |
438 | log_warning_errno(r, "Failed to update $SYSTEMD_EXEC_PID, ignoring: %m"); | |
439 | ||
1d7579c4 LP |
440 | switch (t->type) { |
441 | ||
442 | case TRANSFER_IMPORT_TAR: | |
443 | case TRANSFER_IMPORT_RAW: | |
b6e676ce | 444 | cmd[k++] = SYSTEMD_IMPORT_PATH; |
1d7579c4 LP |
445 | break; |
446 | ||
447 | case TRANSFER_IMPORT_FS: | |
448 | cmd[k++] = SYSTEMD_IMPORT_FS_PATH; | |
449 | break; | |
450 | ||
451 | case TRANSFER_EXPORT_TAR: | |
452 | case TRANSFER_EXPORT_RAW: | |
587fec42 | 453 | cmd[k++] = SYSTEMD_EXPORT_PATH; |
1d7579c4 LP |
454 | break; |
455 | ||
456 | case TRANSFER_PULL_TAR: | |
457 | case TRANSFER_PULL_RAW: | |
b6e676ce | 458 | cmd[k++] = SYSTEMD_PULL_PATH; |
1d7579c4 LP |
459 | break; |
460 | ||
461 | default: | |
04499a70 | 462 | assert_not_reached(); |
1d7579c4 LP |
463 | } |
464 | ||
465 | switch (t->type) { | |
b6e676ce | 466 | |
1d7579c4 LP |
467 | case TRANSFER_IMPORT_TAR: |
468 | case TRANSFER_EXPORT_TAR: | |
469 | case TRANSFER_PULL_TAR: | |
b6e676ce | 470 | cmd[k++] = "tar"; |
1d7579c4 LP |
471 | break; |
472 | ||
473 | case TRANSFER_IMPORT_RAW: | |
474 | case TRANSFER_EXPORT_RAW: | |
475 | case TRANSFER_PULL_RAW: | |
b43d75c3 | 476 | cmd[k++] = "raw"; |
1d7579c4 LP |
477 | break; |
478 | ||
479 | case TRANSFER_IMPORT_FS: | |
480 | cmd[k++] = "run"; | |
481 | break; | |
482 | ||
483 | default: | |
484 | break; | |
485 | } | |
b6e676ce LP |
486 | |
487 | if (t->verify != _IMPORT_VERIFY_INVALID) { | |
488 | cmd[k++] = "--verify"; | |
489 | cmd[k++] = import_verify_to_string(t->verify); | |
490 | } | |
491 | ||
7af5785d LP |
492 | if (t->class != IMAGE_MACHINE) { |
493 | cmd[k++] = "--class"; | |
494 | cmd[k++] = image_class_to_string(t->class); | |
495 | } | |
496 | ||
b146afc4 LP |
497 | if (IN_SET(t->type, TRANSFER_PULL_TAR, TRANSFER_PULL_RAW)) |
498 | cmd[k++] = FLAGS_SET(t->flags, IMPORT_PULL_KEEP_DOWNLOAD) ? | |
499 | "--keep-download=yes" : "--keep-download=no"; | |
500 | ||
7af5785d | 501 | if (FLAGS_SET(t->flags, IMPORT_FORCE)) |
3d7415f4 | 502 | cmd[k++] = "--force"; |
7af5785d | 503 | if (FLAGS_SET(t->flags, IMPORT_READ_ONLY)) |
b6e676ce | 504 | cmd[k++] = "--read-only"; |
3d7415f4 | 505 | |
587fec42 LP |
506 | if (t->format) { |
507 | cmd[k++] = "--format"; | |
508 | cmd[k++] = t->format; | |
509 | } | |
510 | ||
511 | if (!IN_SET(t->type, TRANSFER_EXPORT_TAR, TRANSFER_EXPORT_RAW)) { | |
512 | if (t->remote) | |
513 | cmd[k++] = t->remote; | |
514 | else | |
515 | cmd[k++] = "-"; | |
516 | } | |
b6e676ce | 517 | |
3d7415f4 LP |
518 | if (t->local) |
519 | cmd[k++] = t->local; | |
520 | cmd[k] = NULL; | |
521 | ||
a0afd4e7 LP |
522 | assert(k < ELEMENTSOF(cmd)); |
523 | ||
1a176d5b LP |
524 | if (DEBUG_LOGGING) { |
525 | _cleanup_free_ char *joined = strv_join((char**) cmd, " "); | |
526 | log_debug("Calling: %s", strnull(joined)); | |
527 | } | |
528 | ||
a0afd4e7 LP |
529 | r = invoke_callout_binary(cmd[0], (char * const *) cmd); |
530 | log_error_errno(r, "Failed to execute %s tool: %m", cmd[0]); | |
3d7415f4 LP |
531 | _exit(EXIT_FAILURE); |
532 | } | |
533 | ||
534 | pipefd[1] = safe_close(pipefd[1]); | |
c10d6bdb | 535 | t->log_fd = TAKE_FD(pipefd[0]); |
3d7415f4 | 536 | |
b6e676ce LP |
537 | t->stdin_fd = safe_close(t->stdin_fd); |
538 | ||
09232207 LP |
539 | r = event_add_child_pidref( |
540 | t->manager->event, | |
541 | &t->pid_event_source, | |
542 | &t->pidref, | |
543 | WEXITED, | |
544 | transfer_on_pid, | |
545 | t); | |
3d7415f4 LP |
546 | if (r < 0) |
547 | return r; | |
548 | ||
ab09bf90 ZJS |
549 | r = sd_event_add_io(t->manager->event, &t->log_event_source, |
550 | t->log_fd, EPOLLIN, transfer_on_log, t); | |
3d7415f4 LP |
551 | if (r < 0) |
552 | return r; | |
553 | ||
554 | /* Make sure always process logging before SIGCHLD */ | |
555 | r = sd_event_source_set_priority(t->log_event_source, SD_EVENT_PRIORITY_NORMAL -5); | |
556 | if (r < 0) | |
557 | return r; | |
558 | ||
559 | r = sd_bus_emit_signal( | |
560 | t->manager->bus, | |
561 | "/org/freedesktop/import1", | |
562 | "org.freedesktop.import1.Manager", | |
563 | "TransferNew", | |
564 | "uo", | |
565 | t->id, | |
566 | t->object_path); | |
567 | if (r < 0) | |
568 | return r; | |
569 | ||
570 | return 0; | |
571 | } | |
572 | ||
573 | static Manager *manager_unref(Manager *m) { | |
574 | Transfer *t; | |
575 | ||
576 | if (!m) | |
577 | return NULL; | |
578 | ||
7079cfef LP |
579 | sd_event_source_unref(m->notify_event_source); |
580 | safe_close(m->notify_fd); | |
581 | ||
3d7415f4 LP |
582 | while ((t = hashmap_first(m->transfers))) |
583 | transfer_unref(t); | |
584 | ||
585 | hashmap_free(m->transfers); | |
586 | ||
2a1ffd3e | 587 | hashmap_free(m->polkit_registry); |
3d7415f4 | 588 | |
03976f7b | 589 | m->bus = sd_bus_flush_close_unref(m->bus); |
3d7415f4 LP |
590 | sd_event_unref(m->event); |
591 | ||
6b430fdb | 592 | return mfree(m); |
3d7415f4 LP |
593 | } |
594 | ||
595 | DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref); | |
596 | ||
7079cfef LP |
597 | static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void *userdata) { |
598 | ||
599 | char buf[NOTIFY_BUFFER_MAX+1]; | |
600 | struct iovec iovec = { | |
601 | .iov_base = buf, | |
602 | .iov_len = sizeof(buf)-1, | |
603 | }; | |
fb29cdbe LP |
604 | CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) + |
605 | CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)) control; | |
7079cfef LP |
606 | struct msghdr msghdr = { |
607 | .msg_iov = &iovec, | |
608 | .msg_iovlen = 1, | |
609 | .msg_control = &control, | |
610 | .msg_controllen = sizeof(control), | |
611 | }; | |
371d72e0 | 612 | struct ucred *ucred; |
7079cfef | 613 | Manager *m = userdata; |
7079cfef | 614 | Transfer *t; |
7079cfef | 615 | ssize_t n; |
90f5f355 | 616 | char *p; |
7079cfef LP |
617 | int r; |
618 | ||
3691bcf3 | 619 | n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); |
8add30a0 YW |
620 | if (n < 0) { |
621 | if (ERRNO_IS_TRANSIENT(n)) | |
622 | return 0; | |
3691bcf3 | 623 | return (int) n; |
8add30a0 | 624 | } |
7079cfef | 625 | |
1c8da044 LP |
626 | cmsg_close_all(&msghdr); |
627 | ||
7079cfef LP |
628 | if (msghdr.msg_flags & MSG_TRUNC) { |
629 | log_warning("Got overly long notification datagram, ignoring."); | |
630 | return 0; | |
631 | } | |
632 | ||
371d72e0 | 633 | ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred); |
7079cfef LP |
634 | if (!ucred || ucred->pid <= 0) { |
635 | log_warning("Got notification datagram lacking credential information, ignoring."); | |
636 | return 0; | |
637 | } | |
638 | ||
90e74a66 | 639 | HASHMAP_FOREACH(t, m->transfers) |
09232207 | 640 | if (ucred->pid == t->pidref.pid) |
7079cfef LP |
641 | break; |
642 | ||
643 | if (!t) { | |
644 | log_warning("Got notification datagram from unexpected peer, ignoring."); | |
645 | return 0; | |
646 | } | |
647 | ||
648 | buf[n] = 0; | |
649 | ||
50ed5cbf LP |
650 | p = find_line_startswith(buf, "X_IMPORT_PROGRESS="); |
651 | if (!p) | |
652 | return 0; | |
7079cfef | 653 | |
90f5f355 | 654 | truncate_nl(p); |
7079cfef | 655 | |
5a8582fb LP |
656 | r = parse_percent(p); |
657 | if (r < 0) { | |
a986de68 | 658 | log_warning("Got invalid percent value '%s', ignoring.", p); |
7079cfef LP |
659 | return 0; |
660 | } | |
661 | ||
5a8582fb | 662 | t->progress_percent = (unsigned) r; |
7079cfef | 663 | |
5a8582fb | 664 | log_debug("Got percentage from client: %u%%", t->progress_percent); |
71cb203a LP |
665 | |
666 | transfer_send_progress_update(t); | |
7079cfef LP |
667 | return 0; |
668 | } | |
669 | ||
3d7415f4 LP |
670 | static int manager_new(Manager **ret) { |
671 | _cleanup_(manager_unrefp) Manager *m = NULL; | |
7079cfef LP |
672 | static const union sockaddr_union sa = { |
673 | .un.sun_family = AF_UNIX, | |
674 | .un.sun_path = "/run/systemd/import/notify", | |
675 | }; | |
3d7415f4 LP |
676 | int r; |
677 | ||
678 | assert(ret); | |
679 | ||
c7779a61 | 680 | m = new(Manager, 1); |
3d7415f4 LP |
681 | if (!m) |
682 | return -ENOMEM; | |
683 | ||
c7779a61 IS |
684 | *m = (Manager) { |
685 | .use_btrfs_subvol = true, | |
686 | .use_btrfs_quota = true, | |
687 | }; | |
688 | ||
3d7415f4 LP |
689 | r = sd_event_default(&m->event); |
690 | if (r < 0) | |
691 | return r; | |
692 | ||
423bba99 | 693 | r = sd_event_set_signal_exit(m->event, true); |
82fa9f28 LP |
694 | if (r < 0) |
695 | return r; | |
696 | ||
423bba99 | 697 | r = sd_event_add_signal(m->event, NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, NULL); |
82fa9f28 LP |
698 | if (r < 0) |
699 | return r; | |
700 | ||
701 | r = sd_event_add_memory_pressure(m->event, NULL, NULL, NULL); | |
702 | if (r < 0) | |
703 | log_debug_errno(r, "Failed allocate memory pressure event source, ignoring: %m"); | |
3d7415f4 | 704 | |
423bba99 LP |
705 | r = sd_event_set_watchdog(m->event, true); |
706 | if (r < 0) | |
707 | log_debug_errno(r, "Failed to enable watchdog logic, ignoring: %m"); | |
708 | ||
3d7415f4 LP |
709 | r = sd_bus_default_system(&m->bus); |
710 | if (r < 0) | |
711 | return r; | |
712 | ||
7079cfef LP |
713 | m->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); |
714 | if (m->notify_fd < 0) | |
715 | return -errno; | |
716 | ||
717 | (void) mkdir_parents_label(sa.un.sun_path, 0755); | |
155b6876 | 718 | (void) sockaddr_un_unlink(&sa.un); |
7079cfef | 719 | |
fc2fffe7 | 720 | if (bind(m->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) |
7079cfef LP |
721 | return -errno; |
722 | ||
2ff48e98 LP |
723 | r = setsockopt_int(m->notify_fd, SOL_SOCKET, SO_PASSCRED, true); |
724 | if (r < 0) | |
725 | return r; | |
7079cfef | 726 | |
ab09bf90 ZJS |
727 | r = sd_event_add_io(m->event, &m->notify_event_source, |
728 | m->notify_fd, EPOLLIN, manager_on_notify, m); | |
7079cfef LP |
729 | if (r < 0) |
730 | return r; | |
731 | ||
1cc6c93a | 732 | *ret = TAKE_PTR(m); |
3d7415f4 LP |
733 | |
734 | return 0; | |
735 | } | |
736 | ||
b43d75c3 | 737 | static Transfer *manager_find(Manager *m, TransferType type, const char *remote) { |
3d7415f4 | 738 | Transfer *t; |
3d7415f4 LP |
739 | |
740 | assert(m); | |
741 | assert(type >= 0); | |
742 | assert(type < _TRANSFER_TYPE_MAX); | |
743 | ||
90e74a66 | 744 | HASHMAP_FOREACH(t, m->transfers) |
b0325c99 | 745 | if (t->type == type && streq_ptr(t->remote, remote)) |
3d7415f4 | 746 | return t; |
3d7415f4 LP |
747 | |
748 | return NULL; | |
749 | } | |
750 | ||
19070062 | 751 | static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) { |
b6e676ce | 752 | _cleanup_(transfer_unrefp) Transfer *t = NULL; |
7af5785d | 753 | ImageClass class = _IMAGE_CLASS_INVALID; |
99534007 | 754 | Manager *m = ASSERT_PTR(userdata); |
7af5785d | 755 | const char *local; |
b6e676ce | 756 | TransferType type; |
1209ef94 | 757 | struct stat st; |
7af5785d LP |
758 | uint64_t flags; |
759 | int fd, r; | |
b6e676ce | 760 | |
19070062 | 761 | assert(msg); |
19070062 | 762 | |
b6e676ce LP |
763 | r = bus_verify_polkit_async( |
764 | msg, | |
b6e676ce | 765 | "org.freedesktop.import1.import", |
7b36fb9f | 766 | /* details= */ NULL, |
b6e676ce LP |
767 | &m->polkit_registry, |
768 | error); | |
769 | if (r < 0) | |
770 | return r; | |
771 | if (r == 0) | |
772 | return 1; /* Will call us back */ | |
773 | ||
7af5785d LP |
774 | if (endswith(sd_bus_message_get_member(msg), "Ex")) { |
775 | const char *sclass; | |
776 | ||
777 | r = sd_bus_message_read(msg, "hsst", &fd, &local, &sclass, &flags); | |
778 | if (r < 0) | |
779 | return r; | |
780 | ||
781 | class = image_class_from_string(sclass); | |
782 | if (class < 0) | |
783 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, | |
784 | "Image class '%s' not known", sclass); | |
785 | ||
786 | if (flags & ~(IMPORT_READ_ONLY|IMPORT_FORCE)) | |
787 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, | |
788 | "Flags 0x%" PRIx64 " invalid", flags); | |
789 | } else { | |
790 | int force, read_only; | |
791 | ||
792 | r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only); | |
793 | if (r < 0) | |
794 | return r; | |
795 | ||
796 | class = IMAGE_MACHINE; | |
797 | ||
798 | flags = 0; | |
799 | SET_FLAG(flags, IMPORT_FORCE, force); | |
800 | SET_FLAG(flags, IMPORT_READ_ONLY, read_only); | |
801 | } | |
b6e676ce | 802 | |
c3c892b4 LP |
803 | r = fd_verify_safe_flags(fd); |
804 | if (r < 0) | |
805 | return r; | |
806 | ||
1209ef94 AZ |
807 | if (fstat(fd, &st) < 0) |
808 | return -errno; | |
809 | ||
810 | if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode)) | |
811 | return -EINVAL; | |
176a05c2 | 812 | |
8f20b498 | 813 | if (!image_name_is_valid(local)) |
ab09bf90 | 814 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, |
8f20b498 | 815 | "Local image name %s is invalid", local); |
b6e676ce | 816 | |
7af5785d LP |
817 | if (class == IMAGE_MACHINE) { |
818 | r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota); | |
819 | if (r < 0) | |
820 | return r; | |
821 | } | |
b6e676ce | 822 | |
7af5785d | 823 | type = startswith(sd_bus_message_get_member(msg), "ImportTar") ? |
ab09bf90 | 824 | TRANSFER_IMPORT_TAR : TRANSFER_IMPORT_RAW; |
b6e676ce LP |
825 | |
826 | r = transfer_new(m, &t); | |
827 | if (r < 0) | |
828 | return r; | |
829 | ||
830 | t->type = type; | |
7af5785d LP |
831 | t->class = class; |
832 | t->flags = flags; | |
b6e676ce LP |
833 | |
834 | t->local = strdup(local); | |
835 | if (!t->local) | |
836 | return -ENOMEM; | |
837 | ||
838 | t->stdin_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); | |
839 | if (t->stdin_fd < 0) | |
840 | return -errno; | |
841 | ||
842 | r = transfer_start(t); | |
843 | if (r < 0) | |
844 | return r; | |
845 | ||
7af5785d LP |
846 | r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path); |
847 | if (r < 0) | |
848 | return r; | |
b6e676ce | 849 | |
7af5785d LP |
850 | TAKE_PTR(t); |
851 | return 1; | |
b6e676ce LP |
852 | } |
853 | ||
1d7579c4 LP |
854 | static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *error) { |
855 | _cleanup_(transfer_unrefp) Transfer *t = NULL; | |
7af5785d | 856 | ImageClass class = _IMAGE_CLASS_INVALID; |
99534007 | 857 | Manager *m = ASSERT_PTR(userdata); |
7af5785d LP |
858 | const char *local; |
859 | uint64_t flags; | |
860 | int fd, r; | |
1d7579c4 LP |
861 | |
862 | assert(msg); | |
1d7579c4 LP |
863 | |
864 | r = bus_verify_polkit_async( | |
865 | msg, | |
1d7579c4 | 866 | "org.freedesktop.import1.import", |
7b36fb9f | 867 | /* details= */ NULL, |
1d7579c4 LP |
868 | &m->polkit_registry, |
869 | error); | |
870 | if (r < 0) | |
871 | return r; | |
872 | if (r == 0) | |
873 | return 1; /* Will call us back */ | |
874 | ||
7af5785d LP |
875 | if (endswith(sd_bus_message_get_member(msg), "Ex")) { |
876 | const char *sclass; | |
877 | ||
878 | r = sd_bus_message_read(msg, "hsst", &fd, &local, &sclass, &flags); | |
879 | if (r < 0) | |
880 | return r; | |
881 | ||
882 | class = image_class_from_string(sclass); | |
883 | if (class < 0) | |
884 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, | |
885 | "Image class '%s' not known", sclass); | |
886 | ||
887 | if (flags & ~(IMPORT_READ_ONLY|IMPORT_FORCE)) | |
888 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, | |
889 | "Flags 0x%" PRIx64 " invalid", flags); | |
890 | } else { | |
891 | int force, read_only; | |
892 | ||
893 | r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only); | |
894 | if (r < 0) | |
895 | return r; | |
896 | ||
897 | class = IMAGE_MACHINE; | |
898 | ||
899 | flags = 0; | |
900 | SET_FLAG(flags, IMPORT_FORCE, force); | |
901 | SET_FLAG(flags, IMPORT_READ_ONLY, read_only); | |
902 | } | |
1d7579c4 | 903 | |
9f65355b | 904 | r = fd_verify_safe_flags_full(fd, O_DIRECTORY); |
c3c892b4 LP |
905 | if (r < 0) |
906 | return r; | |
907 | ||
176a05c2 LP |
908 | r = fd_verify_directory(fd); |
909 | if (r < 0) | |
910 | return r; | |
911 | ||
8f20b498 | 912 | if (!image_name_is_valid(local)) |
ab09bf90 | 913 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, |
8f20b498 | 914 | "Local image name %s is invalid", local); |
1d7579c4 | 915 | |
7af5785d LP |
916 | if (class == IMAGE_MACHINE) { |
917 | r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota); | |
918 | if (r < 0) | |
919 | return r; | |
920 | } | |
1d7579c4 LP |
921 | |
922 | r = transfer_new(m, &t); | |
923 | if (r < 0) | |
924 | return r; | |
925 | ||
926 | t->type = TRANSFER_IMPORT_FS; | |
7af5785d LP |
927 | t->class = class; |
928 | t->flags = flags; | |
1d7579c4 LP |
929 | |
930 | t->local = strdup(local); | |
931 | if (!t->local) | |
932 | return -ENOMEM; | |
933 | ||
934 | t->stdin_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); | |
935 | if (t->stdin_fd < 0) | |
936 | return -errno; | |
937 | ||
938 | r = transfer_start(t); | |
939 | if (r < 0) | |
940 | return r; | |
941 | ||
7af5785d LP |
942 | r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path); |
943 | if (r < 0) | |
944 | return r; | |
1d7579c4 | 945 | |
7af5785d LP |
946 | TAKE_PTR(t); |
947 | return 1; | |
1d7579c4 LP |
948 | } |
949 | ||
19070062 | 950 | static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) { |
587fec42 | 951 | _cleanup_(transfer_unrefp) Transfer *t = NULL; |
7af5785d | 952 | ImageClass class = _IMAGE_CLASS_INVALID; |
99534007 | 953 | Manager *m = ASSERT_PTR(userdata); |
7af5785d | 954 | const char *local, *format; |
587fec42 | 955 | TransferType type; |
7af5785d | 956 | uint64_t flags; |
1209ef94 | 957 | struct stat st; |
7af5785d | 958 | int fd, r; |
587fec42 | 959 | |
19070062 | 960 | assert(msg); |
19070062 | 961 | |
587fec42 LP |
962 | r = bus_verify_polkit_async( |
963 | msg, | |
587fec42 | 964 | "org.freedesktop.import1.export", |
7b36fb9f | 965 | /* details= */ NULL, |
587fec42 LP |
966 | &m->polkit_registry, |
967 | error); | |
968 | if (r < 0) | |
969 | return r; | |
970 | if (r == 0) | |
971 | return 1; /* Will call us back */ | |
972 | ||
7af5785d LP |
973 | if (endswith(sd_bus_message_get_member(msg), "Ex")) { |
974 | const char *sclass; | |
975 | ||
976 | r = sd_bus_message_read(msg, "sshst", &local, &sclass, &fd, &format, &flags); | |
977 | if (r < 0) | |
978 | return r; | |
979 | ||
980 | class = image_class_from_string(sclass); | |
981 | if (class < 0) | |
982 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, | |
983 | "Image class '%s' not known", sclass); | |
984 | ||
985 | if (flags != 0) | |
986 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, | |
987 | "Flags 0x%" PRIx64 " invalid", flags); | |
988 | } else { | |
989 | r = sd_bus_message_read(msg, "shs", &local, &fd, &format); | |
990 | if (r < 0) | |
991 | return r; | |
992 | ||
993 | class = IMAGE_MACHINE; | |
994 | flags = 0; | |
995 | } | |
587fec42 | 996 | |
8f20b498 | 997 | if (!image_name_is_valid(local)) |
ab09bf90 | 998 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, |
8f20b498 | 999 | "Local image name %s is invalid", local); |
587fec42 | 1000 | |
c3c892b4 LP |
1001 | r = fd_verify_safe_flags(fd); |
1002 | if (r < 0) | |
1003 | return r; | |
1004 | ||
1209ef94 AZ |
1005 | if (fstat(fd, &st) < 0) |
1006 | return -errno; | |
1007 | ||
1008 | if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode)) | |
1009 | return -EINVAL; | |
176a05c2 | 1010 | |
7af5785d | 1011 | type = startswith(sd_bus_message_get_member(msg), "ExportTar") ? |
ab09bf90 | 1012 | TRANSFER_EXPORT_TAR : TRANSFER_EXPORT_RAW; |
587fec42 LP |
1013 | |
1014 | r = transfer_new(m, &t); | |
1015 | if (r < 0) | |
1016 | return r; | |
1017 | ||
1018 | t->type = type; | |
7af5785d LP |
1019 | t->class = class; |
1020 | t->flags = flags; | |
587fec42 LP |
1021 | |
1022 | if (!isempty(format)) { | |
1023 | t->format = strdup(format); | |
1024 | if (!t->format) | |
1025 | return -ENOMEM; | |
1026 | } | |
1027 | ||
1028 | t->local = strdup(local); | |
1029 | if (!t->local) | |
1030 | return -ENOMEM; | |
1031 | ||
1032 | t->stdout_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); | |
1033 | if (t->stdout_fd < 0) | |
1034 | return -errno; | |
1035 | ||
1036 | r = transfer_start(t); | |
1037 | if (r < 0) | |
1038 | return r; | |
1039 | ||
7af5785d LP |
1040 | r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path); |
1041 | if (r < 0) | |
1042 | return r; | |
587fec42 | 1043 | |
7af5785d LP |
1044 | TAKE_PTR(t); |
1045 | return 1; | |
587fec42 LP |
1046 | } |
1047 | ||
19070062 | 1048 | static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) { |
3d7415f4 | 1049 | _cleanup_(transfer_unrefp) Transfer *t = NULL; |
7af5785d LP |
1050 | ImageClass class = _IMAGE_CLASS_INVALID; |
1051 | const char *remote, *local, *verify; | |
99534007 | 1052 | Manager *m = ASSERT_PTR(userdata); |
3d7415f4 | 1053 | TransferType type; |
7af5785d LP |
1054 | uint64_t flags; |
1055 | ImportVerify v; | |
1056 | int r; | |
3d7415f4 | 1057 | |
3d7415f4 | 1058 | assert(msg); |
3d7415f4 LP |
1059 | |
1060 | r = bus_verify_polkit_async( | |
1061 | msg, | |
3d7415f4 | 1062 | "org.freedesktop.import1.pull", |
7b36fb9f | 1063 | /* details= */ NULL, |
3d7415f4 LP |
1064 | &m->polkit_registry, |
1065 | error); | |
1066 | if (r < 0) | |
1067 | return r; | |
1068 | if (r == 0) | |
1069 | return 1; /* Will call us back */ | |
1070 | ||
7af5785d LP |
1071 | if (endswith(sd_bus_message_get_member(msg), "Ex")) { |
1072 | const char *sclass; | |
1073 | ||
1074 | r = sd_bus_message_read(msg, "sssst", &remote, &local, &sclass, &verify, &flags); | |
1075 | if (r < 0) | |
1076 | return r; | |
1077 | ||
1078 | class = image_class_from_string(sclass); | |
1079 | if (class < 0) | |
1080 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, | |
1081 | "Image class '%s' not known", sclass); | |
1082 | ||
b146afc4 | 1083 | if (flags & ~(IMPORT_FORCE|IMPORT_READ_ONLY|IMPORT_PULL_KEEP_DOWNLOAD)) |
7af5785d LP |
1084 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, |
1085 | "Flags 0x%" PRIx64 " invalid", flags); | |
1086 | } else { | |
1087 | int force; | |
1088 | ||
1089 | r = sd_bus_message_read(msg, "sssb", &remote, &local, &verify, &force); | |
1090 | if (r < 0) | |
1091 | return r; | |
1092 | ||
1093 | class = IMAGE_MACHINE; | |
1094 | ||
1095 | flags = 0; | |
1096 | SET_FLAG(flags, IMPORT_FORCE, force); | |
1097 | } | |
3d7415f4 | 1098 | |
c456862f | 1099 | if (!http_url_is_valid(remote) && !file_url_is_valid(remote)) |
ab09bf90 ZJS |
1100 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, |
1101 | "URL %s is invalid", remote); | |
3d7415f4 LP |
1102 | |
1103 | if (isempty(local)) | |
1104 | local = NULL; | |
8f20b498 | 1105 | else if (!image_name_is_valid(local)) |
ab09bf90 | 1106 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, |
8f20b498 | 1107 | "Local image name %s is invalid", local); |
3d7415f4 LP |
1108 | |
1109 | if (isempty(verify)) | |
1110 | v = IMPORT_VERIFY_SIGNATURE; | |
1111 | else | |
1112 | v = import_verify_from_string(verify); | |
1113 | if (v < 0) | |
ab09bf90 ZJS |
1114 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, |
1115 | "Unknown verification mode %s", verify); | |
3d7415f4 | 1116 | |
7af5785d LP |
1117 | if (class == IMAGE_MACHINE) { |
1118 | r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota); | |
1119 | if (r < 0) | |
1120 | return r; | |
1121 | } | |
ce06fdfb | 1122 | |
7af5785d | 1123 | type = startswith(sd_bus_message_get_member(msg), "PullTar") ? |
ab09bf90 | 1124 | TRANSFER_PULL_TAR : TRANSFER_PULL_RAW; |
3d7415f4 | 1125 | |
b43d75c3 | 1126 | if (manager_find(m, type, remote)) |
ab09bf90 ZJS |
1127 | return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS, |
1128 | "Transfer for %s already in progress.", remote); | |
3d7415f4 LP |
1129 | |
1130 | r = transfer_new(m, &t); | |
1131 | if (r < 0) | |
1132 | return r; | |
1133 | ||
1134 | t->type = type; | |
1135 | t->verify = v; | |
7af5785d LP |
1136 | t->flags = flags; |
1137 | t->class = class; | |
3d7415f4 LP |
1138 | |
1139 | t->remote = strdup(remote); | |
1140 | if (!t->remote) | |
1141 | return -ENOMEM; | |
1142 | ||
b6e676ce LP |
1143 | if (local) { |
1144 | t->local = strdup(local); | |
1145 | if (!t->local) | |
1146 | return -ENOMEM; | |
1147 | } | |
3d7415f4 LP |
1148 | |
1149 | r = transfer_start(t); | |
1150 | if (r < 0) | |
1151 | return r; | |
1152 | ||
7af5785d LP |
1153 | r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path); |
1154 | if (r < 0) | |
1155 | return r; | |
3d7415f4 | 1156 | |
7af5785d LP |
1157 | TAKE_PTR(t); |
1158 | return 1; | |
3d7415f4 LP |
1159 | } |
1160 | ||
19070062 | 1161 | static int method_list_transfers(sd_bus_message *msg, void *userdata, sd_bus_error *error) { |
4afd3348 | 1162 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; |
99534007 | 1163 | Manager *m = ASSERT_PTR(userdata); |
7af5785d | 1164 | ImageClass class = _IMAGE_CLASS_INVALID; |
3d7415f4 | 1165 | Transfer *t; |
3d7415f4 LP |
1166 | int r; |
1167 | ||
3d7415f4 | 1168 | assert(msg); |
3d7415f4 | 1169 | |
7af5785d LP |
1170 | bool ex = endswith(sd_bus_message_get_member(msg), "Ex"); |
1171 | if (ex) { | |
1172 | const char *sclass; | |
1173 | uint64_t flags; | |
1174 | ||
1175 | r = sd_bus_message_read(msg, "st", &sclass, &flags); | |
1176 | if (r < 0) | |
1177 | return bus_log_parse_error(r); | |
1178 | ||
1179 | if (!isempty(sclass)) { | |
1180 | class = image_class_from_string(sclass); | |
1181 | if (class < 0) | |
1182 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, | |
1183 | "Image class '%s' not known", sclass); | |
1184 | } | |
1185 | ||
1186 | if (flags != 0) | |
1187 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, | |
1188 | "Flags 0x%" PRIx64 " invalid", flags); | |
1189 | } | |
1190 | ||
3d7415f4 LP |
1191 | r = sd_bus_message_new_method_return(msg, &reply); |
1192 | if (r < 0) | |
1193 | return r; | |
1194 | ||
7af5785d LP |
1195 | if (ex) |
1196 | r = sd_bus_message_open_container(reply, 'a', "(ussssdo)"); | |
1197 | else | |
1198 | r = sd_bus_message_open_container(reply, 'a', "(usssdo)"); | |
3d7415f4 LP |
1199 | if (r < 0) |
1200 | return r; | |
1201 | ||
90e74a66 | 1202 | HASHMAP_FOREACH(t, m->transfers) { |
3d7415f4 | 1203 | |
7af5785d LP |
1204 | if (class >= 0 && class != t->class) |
1205 | continue; | |
1206 | ||
1207 | if (ex) | |
1208 | r = sd_bus_message_append( | |
1209 | reply, | |
1210 | "(ussssdo)", | |
1211 | t->id, | |
1212 | transfer_type_to_string(t->type), | |
1213 | t->remote, | |
1214 | t->local, | |
1215 | image_class_to_string(t->class), | |
1216 | transfer_percent_as_double(t), | |
1217 | t->object_path); | |
1218 | else | |
1219 | r = sd_bus_message_append( | |
1220 | reply, | |
1221 | "(usssdo)", | |
1222 | t->id, | |
1223 | transfer_type_to_string(t->type), | |
1224 | t->remote, | |
1225 | t->local, | |
1226 | transfer_percent_as_double(t), | |
1227 | t->object_path); | |
3d7415f4 LP |
1228 | if (r < 0) |
1229 | return r; | |
1230 | } | |
1231 | ||
1232 | r = sd_bus_message_close_container(reply); | |
1233 | if (r < 0) | |
1234 | return r; | |
1235 | ||
9030ca46 | 1236 | return sd_bus_send(NULL, reply, NULL); |
3d7415f4 LP |
1237 | } |
1238 | ||
19070062 | 1239 | static int method_cancel(sd_bus_message *msg, void *userdata, sd_bus_error *error) { |
99534007 | 1240 | Transfer *t = ASSERT_PTR(userdata); |
3d7415f4 LP |
1241 | int r; |
1242 | ||
3d7415f4 | 1243 | assert(msg); |
3d7415f4 LP |
1244 | |
1245 | r = bus_verify_polkit_async( | |
1246 | msg, | |
3d7415f4 | 1247 | "org.freedesktop.import1.pull", |
7b36fb9f | 1248 | /* details= */ NULL, |
3d7415f4 LP |
1249 | &t->manager->polkit_registry, |
1250 | error); | |
1251 | if (r < 0) | |
1252 | return r; | |
1253 | if (r == 0) | |
1254 | return 1; /* Will call us back */ | |
1255 | ||
1256 | r = transfer_cancel(t); | |
1257 | if (r < 0) | |
1258 | return r; | |
1259 | ||
1260 | return sd_bus_reply_method_return(msg, NULL); | |
1261 | } | |
1262 | ||
19070062 | 1263 | static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_error *error) { |
99534007 | 1264 | Manager *m = ASSERT_PTR(userdata); |
3d7415f4 LP |
1265 | Transfer *t; |
1266 | uint32_t id; | |
1267 | int r; | |
1268 | ||
3d7415f4 | 1269 | assert(msg); |
3d7415f4 LP |
1270 | |
1271 | r = bus_verify_polkit_async( | |
1272 | msg, | |
7af5785d | 1273 | "org.freedesktop.import1.cancel", |
7b36fb9f | 1274 | /* details= */ NULL, |
3d7415f4 LP |
1275 | &m->polkit_registry, |
1276 | error); | |
1277 | if (r < 0) | |
1278 | return r; | |
1279 | if (r == 0) | |
1280 | return 1; /* Will call us back */ | |
1281 | ||
1282 | r = sd_bus_message_read(msg, "u", &id); | |
1283 | if (r < 0) | |
1284 | return r; | |
1285 | if (id <= 0) | |
1b09b81c | 1286 | return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid transfer id"); |
3d7415f4 LP |
1287 | |
1288 | t = hashmap_get(m->transfers, UINT32_TO_PTR(id)); | |
1289 | if (!t) | |
09d46cfd | 1290 | return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_TRANSFER, "No transfer by id %" PRIu32, id); |
3d7415f4 LP |
1291 | |
1292 | r = transfer_cancel(t); | |
1293 | if (r < 0) | |
1294 | return r; | |
1295 | ||
1296 | return sd_bus_reply_method_return(msg, NULL); | |
1297 | } | |
1298 | ||
5b7bfe06 LP |
1299 | static int method_list_images(sd_bus_message *msg, void *userdata, sd_bus_error *error) { |
1300 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; | |
1301 | ImageClass class = _IMAGE_CLASS_INVALID; | |
1302 | int r; | |
1303 | ||
1304 | assert(msg); | |
1305 | ||
1306 | const char *sclass; | |
1307 | uint64_t flags; | |
1308 | ||
1309 | r = sd_bus_message_read(msg, "st", &sclass, &flags); | |
1310 | if (r < 0) | |
1311 | return r; | |
1312 | ||
1313 | if (!isempty(sclass)) { | |
1314 | class = image_class_from_string(sclass); | |
1315 | if (class < 0) | |
1316 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, | |
1317 | "Image class '%s' not known", sclass); | |
1318 | } | |
1319 | ||
1320 | if (flags != 0) | |
1321 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, | |
1322 | "Flags 0x%" PRIx64 " invalid", flags); | |
1323 | ||
1324 | r = sd_bus_message_new_method_return(msg, &reply); | |
1325 | if (r < 0) | |
1326 | return r; | |
1327 | ||
1328 | r = sd_bus_message_open_container(reply, 'a', "(ssssbtttttt)"); | |
1329 | if (r < 0) | |
1330 | return r; | |
1331 | ||
1332 | for (ImageClass c = class < 0 ? 0 : class; | |
1333 | class < 0 ? (c < _IMAGE_CLASS_MAX) : (c == class); | |
1334 | c++) { | |
1335 | ||
1336 | _cleanup_(hashmap_freep) Hashmap *h = NULL; | |
1337 | ||
1338 | h = hashmap_new(&image_hash_ops); | |
1339 | if (!h) | |
1340 | return -ENOMEM; | |
1341 | ||
1342 | r = image_discover(c, /* root= */ NULL, h); | |
1343 | if (r < 0) { | |
1344 | if (class >= 0) | |
1345 | return r; | |
1346 | ||
1347 | log_warning_errno(r, "Failed to discover images of type %s: %m", image_class_to_string(c)); | |
1348 | continue; | |
1349 | } | |
1350 | ||
1351 | Image *i; | |
1352 | HASHMAP_FOREACH(i, h) { | |
1353 | r = sd_bus_message_append( | |
1354 | reply, | |
1355 | "(ssssbtttttt)", | |
1356 | image_class_to_string(i->class), | |
1357 | i->name, | |
1358 | image_type_to_string(i->type), | |
1359 | i->path, | |
1360 | i->read_only, | |
1361 | i->crtime, | |
1362 | i->mtime, | |
1363 | i->usage, | |
1364 | i->usage_exclusive, | |
1365 | i->limit, | |
1366 | i->limit_exclusive); | |
1367 | if (r < 0) | |
1368 | return r; | |
1369 | } | |
1370 | } | |
1371 | ||
1372 | r = sd_bus_message_close_container(reply); | |
1373 | if (r < 0) | |
1374 | return r; | |
1375 | ||
1376 | return sd_bus_send(NULL, reply, NULL); | |
1377 | } | |
1378 | ||
7079cfef LP |
1379 | static int property_get_progress( |
1380 | sd_bus *bus, | |
1381 | const char *path, | |
1382 | const char *interface, | |
1383 | const char *property, | |
1384 | sd_bus_message *reply, | |
1385 | void *userdata, | |
1386 | sd_bus_error *error) { | |
1387 | ||
99534007 | 1388 | Transfer *t = ASSERT_PTR(userdata); |
7079cfef LP |
1389 | |
1390 | assert(bus); | |
1391 | assert(reply); | |
7079cfef | 1392 | |
1d7579c4 | 1393 | return sd_bus_message_append(reply, "d", transfer_percent_as_double(t)); |
7079cfef LP |
1394 | } |
1395 | ||
3d7415f4 LP |
1396 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, transfer_type, TransferType); |
1397 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_verify, import_verify, ImportVerify); | |
1398 | ||
a3b7cf50 ZJS |
1399 | static int transfer_object_find( |
1400 | sd_bus *bus, | |
1401 | const char *path, | |
1402 | const char *interface, | |
1403 | void *userdata, | |
1404 | void **found, | |
1405 | sd_bus_error *error) { | |
1406 | ||
99534007 | 1407 | Manager *m = ASSERT_PTR(userdata); |
a3b7cf50 ZJS |
1408 | Transfer *t; |
1409 | const char *p; | |
1410 | uint32_t id; | |
1411 | int r; | |
1412 | ||
1413 | assert(bus); | |
1414 | assert(path); | |
1415 | assert(interface); | |
1416 | assert(found); | |
a3b7cf50 ZJS |
1417 | |
1418 | p = startswith(path, "/org/freedesktop/import1/transfer/_"); | |
1419 | if (!p) | |
1420 | return 0; | |
1421 | ||
1422 | r = safe_atou32(p, &id); | |
1423 | if (r < 0 || id == 0) | |
1424 | return 0; | |
1425 | ||
1426 | t = hashmap_get(m->transfers, UINT32_TO_PTR(id)); | |
1427 | if (!t) | |
1428 | return 0; | |
1429 | ||
1430 | *found = t; | |
1431 | return 1; | |
1432 | } | |
1433 | ||
1434 | static int transfer_node_enumerator( | |
1435 | sd_bus *bus, | |
1436 | const char *path, | |
1437 | void *userdata, | |
1438 | char ***nodes, | |
1439 | sd_bus_error *error) { | |
1440 | ||
1441 | _cleanup_strv_free_ char **l = NULL; | |
1442 | Manager *m = userdata; | |
1443 | Transfer *t; | |
1444 | unsigned k = 0; | |
a3b7cf50 ZJS |
1445 | |
1446 | l = new0(char*, hashmap_size(m->transfers) + 1); | |
1447 | if (!l) | |
1448 | return -ENOMEM; | |
1449 | ||
90e74a66 | 1450 | HASHMAP_FOREACH(t, m->transfers) { |
a3b7cf50 ZJS |
1451 | |
1452 | l[k] = strdup(t->object_path); | |
1453 | if (!l[k]) | |
1454 | return -ENOMEM; | |
1455 | ||
1456 | k++; | |
1457 | } | |
1458 | ||
1459 | *nodes = TAKE_PTR(l); | |
1460 | ||
1461 | return 1; | |
1462 | } | |
1463 | ||
3d7415f4 LP |
1464 | static const sd_bus_vtable transfer_vtable[] = { |
1465 | SD_BUS_VTABLE_START(0), | |
956ecd3c | 1466 | |
3d7415f4 LP |
1467 | SD_BUS_PROPERTY("Id", "u", NULL, offsetof(Transfer, id), SD_BUS_VTABLE_PROPERTY_CONST), |
1468 | SD_BUS_PROPERTY("Local", "s", NULL, offsetof(Transfer, local), SD_BUS_VTABLE_PROPERTY_CONST), | |
1469 | SD_BUS_PROPERTY("Remote", "s", NULL, offsetof(Transfer, remote), SD_BUS_VTABLE_PROPERTY_CONST), | |
1470 | SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Transfer, type), SD_BUS_VTABLE_PROPERTY_CONST), | |
1471 | SD_BUS_PROPERTY("Verify", "s", property_get_verify, offsetof(Transfer, verify), SD_BUS_VTABLE_PROPERTY_CONST), | |
7079cfef | 1472 | SD_BUS_PROPERTY("Progress", "d", property_get_progress, 0, 0), |
956ecd3c | 1473 | |
3d7415f4 | 1474 | SD_BUS_METHOD("Cancel", NULL, NULL, method_cancel, SD_BUS_VTABLE_UNPRIVILEGED), |
956ecd3c ZJS |
1475 | |
1476 | SD_BUS_SIGNAL_WITH_NAMES("LogMessage", | |
1477 | "us", | |
1478 | SD_BUS_PARAM(priority) | |
1479 | SD_BUS_PARAM(line), | |
1480 | 0), | |
71cb203a LP |
1481 | SD_BUS_SIGNAL_WITH_NAMES("ProgressUpdate", |
1482 | "d", | |
1483 | SD_BUS_PARAM(progress), | |
1484 | 0), | |
956ecd3c | 1485 | |
3d7415f4 LP |
1486 | SD_BUS_VTABLE_END, |
1487 | }; | |
1488 | ||
a3b7cf50 ZJS |
1489 | static const BusObjectImplementation transfer_object = { |
1490 | "/org/freedesktop/import1/transfer", | |
1491 | "org.freedesktop.import1.Transfer", | |
1492 | .fallback_vtables = BUS_FALLBACK_VTABLES({transfer_vtable, transfer_object_find}), | |
1493 | .node_enumerator = transfer_node_enumerator, | |
1494 | }; | |
1495 | ||
3d7415f4 LP |
1496 | static const sd_bus_vtable manager_vtable[] = { |
1497 | SD_BUS_VTABLE_START(0), | |
956ecd3c ZJS |
1498 | |
1499 | SD_BUS_METHOD_WITH_NAMES("ImportTar", | |
1500 | "hsbb", | |
1501 | SD_BUS_PARAM(fd) | |
1502 | SD_BUS_PARAM(local_name) | |
1503 | SD_BUS_PARAM(force) | |
1504 | SD_BUS_PARAM(read_only), | |
1505 | "uo", | |
1506 | SD_BUS_PARAM(transfer_id) | |
1507 | SD_BUS_PARAM(transfer_path), | |
1508 | method_import_tar_or_raw, | |
1509 | SD_BUS_VTABLE_UNPRIVILEGED), | |
7af5785d LP |
1510 | SD_BUS_METHOD_WITH_NAMES("ImportTarEx", |
1511 | "hsst", | |
1512 | SD_BUS_PARAM(fd) | |
1513 | SD_BUS_PARAM(local_name) | |
1514 | SD_BUS_PARAM(class) | |
1515 | SD_BUS_PARAM(flags), | |
1516 | "uo", | |
1517 | SD_BUS_PARAM(transfer_id) | |
1518 | SD_BUS_PARAM(transfer_path), | |
1519 | method_import_tar_or_raw, | |
1520 | SD_BUS_VTABLE_UNPRIVILEGED), | |
956ecd3c ZJS |
1521 | SD_BUS_METHOD_WITH_NAMES("ImportRaw", |
1522 | "hsbb", | |
1523 | SD_BUS_PARAM(fd) | |
1524 | SD_BUS_PARAM(local_name) | |
1525 | SD_BUS_PARAM(force) | |
1526 | SD_BUS_PARAM(read_only), | |
1527 | "uo", | |
1528 | SD_BUS_PARAM(transfer_id) | |
1529 | SD_BUS_PARAM(transfer_path), | |
1530 | method_import_tar_or_raw, | |
1531 | SD_BUS_VTABLE_UNPRIVILEGED), | |
7af5785d LP |
1532 | SD_BUS_METHOD_WITH_NAMES("ImportRawEx", |
1533 | "hsst", | |
1534 | SD_BUS_PARAM(fd) | |
1535 | SD_BUS_PARAM(local_name) | |
1536 | SD_BUS_PARAM(class) | |
1537 | SD_BUS_PARAM(flags), | |
1538 | "uo", | |
1539 | SD_BUS_PARAM(transfer_id) | |
1540 | SD_BUS_PARAM(transfer_path), | |
1541 | method_import_tar_or_raw, | |
1542 | SD_BUS_VTABLE_UNPRIVILEGED), | |
956ecd3c ZJS |
1543 | SD_BUS_METHOD_WITH_NAMES("ImportFileSystem", |
1544 | "hsbb", | |
1545 | SD_BUS_PARAM(fd) | |
1546 | SD_BUS_PARAM(local_name) | |
1547 | SD_BUS_PARAM(force) | |
1548 | SD_BUS_PARAM(read_only), | |
1549 | "uo", | |
1550 | SD_BUS_PARAM(transfer_id) | |
1551 | SD_BUS_PARAM(transfer_path), | |
1552 | method_import_fs, | |
1553 | SD_BUS_VTABLE_UNPRIVILEGED), | |
7af5785d LP |
1554 | SD_BUS_METHOD_WITH_NAMES("ImportFileSystemEx", |
1555 | "hsst", | |
1556 | SD_BUS_PARAM(fd) | |
1557 | SD_BUS_PARAM(local_name) | |
1558 | SD_BUS_PARAM(class) | |
1559 | SD_BUS_PARAM(flags), | |
1560 | "uo", | |
1561 | SD_BUS_PARAM(transfer_id) | |
1562 | SD_BUS_PARAM(transfer_path), | |
1563 | method_import_fs, | |
1564 | SD_BUS_VTABLE_UNPRIVILEGED), | |
956ecd3c ZJS |
1565 | SD_BUS_METHOD_WITH_NAMES("ExportTar", |
1566 | "shs", | |
1567 | SD_BUS_PARAM(local_name) | |
1568 | SD_BUS_PARAM(fd) | |
1569 | SD_BUS_PARAM(format), | |
1570 | "uo", | |
1571 | SD_BUS_PARAM(transfer_id) | |
1572 | SD_BUS_PARAM(transfer_path), | |
1573 | method_export_tar_or_raw, | |
1574 | SD_BUS_VTABLE_UNPRIVILEGED), | |
7af5785d LP |
1575 | SD_BUS_METHOD_WITH_NAMES("ExportTarEx", |
1576 | "sshst", | |
1577 | SD_BUS_PARAM(local_name) | |
1578 | SD_BUS_PARAM(class) | |
1579 | SD_BUS_PARAM(fd) | |
1580 | SD_BUS_PARAM(format) | |
1581 | SD_BUS_PARAM(flags), | |
1582 | "uo", | |
1583 | SD_BUS_PARAM(transfer_id) | |
1584 | SD_BUS_PARAM(transfer_path), | |
1585 | method_export_tar_or_raw, | |
1586 | SD_BUS_VTABLE_UNPRIVILEGED), | |
956ecd3c ZJS |
1587 | SD_BUS_METHOD_WITH_NAMES("ExportRaw", |
1588 | "shs", | |
1589 | SD_BUS_PARAM(local_name) | |
1590 | SD_BUS_PARAM(fd) | |
1591 | SD_BUS_PARAM(format), | |
1592 | "uo", | |
1593 | SD_BUS_PARAM(transfer_id) | |
1594 | SD_BUS_PARAM(transfer_path), | |
1595 | method_export_tar_or_raw, | |
1596 | SD_BUS_VTABLE_UNPRIVILEGED), | |
7af5785d LP |
1597 | SD_BUS_METHOD_WITH_NAMES("ExportRawEx", |
1598 | "sshst", | |
1599 | SD_BUS_PARAM(local_name) | |
1600 | SD_BUS_PARAM(class) | |
1601 | SD_BUS_PARAM(fd) | |
1602 | SD_BUS_PARAM(format) | |
1603 | SD_BUS_PARAM(flags), | |
1604 | "uo", | |
1605 | SD_BUS_PARAM(transfer_id) | |
1606 | SD_BUS_PARAM(transfer_path), | |
1607 | method_export_tar_or_raw, | |
1608 | SD_BUS_VTABLE_UNPRIVILEGED), | |
956ecd3c ZJS |
1609 | SD_BUS_METHOD_WITH_NAMES("PullTar", |
1610 | "sssb", | |
1611 | SD_BUS_PARAM(url) | |
1612 | SD_BUS_PARAM(local_name) | |
1613 | SD_BUS_PARAM(verify_mode) | |
1614 | SD_BUS_PARAM(force), | |
1615 | "uo", | |
1616 | SD_BUS_PARAM(transfer_id) | |
1617 | SD_BUS_PARAM(transfer_path), | |
1618 | method_pull_tar_or_raw, | |
1619 | SD_BUS_VTABLE_UNPRIVILEGED), | |
7af5785d LP |
1620 | SD_BUS_METHOD_WITH_NAMES("PullTarEx", |
1621 | "sssst", | |
1622 | SD_BUS_PARAM(url) | |
1623 | SD_BUS_PARAM(local_name) | |
1624 | SD_BUS_PARAM(class) | |
1625 | SD_BUS_PARAM(verify_mode) | |
1626 | SD_BUS_PARAM(flags), | |
1627 | "uo", | |
1628 | SD_BUS_PARAM(transfer_id) | |
1629 | SD_BUS_PARAM(transfer_path), | |
1630 | method_pull_tar_or_raw, | |
1631 | SD_BUS_VTABLE_UNPRIVILEGED), | |
956ecd3c ZJS |
1632 | SD_BUS_METHOD_WITH_NAMES("PullRaw", |
1633 | "sssb", | |
1634 | SD_BUS_PARAM(url) | |
1635 | SD_BUS_PARAM(local_name) | |
1636 | SD_BUS_PARAM(verify_mode) | |
1637 | SD_BUS_PARAM(force), | |
1638 | "uo", | |
1639 | SD_BUS_PARAM(transfer_id) | |
1640 | SD_BUS_PARAM(transfer_path), | |
1641 | method_pull_tar_or_raw, | |
1642 | SD_BUS_VTABLE_UNPRIVILEGED), | |
7af5785d LP |
1643 | SD_BUS_METHOD_WITH_NAMES("PullRawEx", |
1644 | "sssst", | |
1645 | SD_BUS_PARAM(url) | |
1646 | SD_BUS_PARAM(local_name) | |
1647 | SD_BUS_PARAM(class) | |
1648 | SD_BUS_PARAM(verify_mode) | |
1649 | SD_BUS_PARAM(flags), | |
1650 | "uo", | |
1651 | SD_BUS_PARAM(transfer_id) | |
1652 | SD_BUS_PARAM(transfer_path), | |
1653 | method_pull_tar_or_raw, | |
1654 | SD_BUS_VTABLE_UNPRIVILEGED), | |
956ecd3c ZJS |
1655 | SD_BUS_METHOD_WITH_NAMES("ListTransfers", |
1656 | NULL,, | |
1657 | "a(usssdo)", | |
1658 | SD_BUS_PARAM(transfers), | |
1659 | method_list_transfers, | |
1660 | SD_BUS_VTABLE_UNPRIVILEGED), | |
7af5785d LP |
1661 | SD_BUS_METHOD_WITH_NAMES("ListTransfersEx", |
1662 | "st", | |
1663 | SD_BUS_PARAM(class) | |
1664 | SD_BUS_PARAM(flags), | |
1665 | "a(ussssdo)", | |
1666 | SD_BUS_PARAM(transfers), | |
1667 | method_list_transfers, | |
1668 | SD_BUS_VTABLE_UNPRIVILEGED), | |
956ecd3c ZJS |
1669 | SD_BUS_METHOD_WITH_NAMES("CancelTransfer", |
1670 | "u", | |
1671 | SD_BUS_PARAM(transfer_id), | |
1672 | NULL,, | |
1673 | method_cancel_transfer, | |
1674 | SD_BUS_VTABLE_UNPRIVILEGED), | |
5b7bfe06 LP |
1675 | SD_BUS_METHOD_WITH_NAMES("ListImages", |
1676 | "st", | |
1677 | SD_BUS_PARAM(class) | |
1678 | SD_BUS_PARAM(flags), | |
1679 | "a(ssssbtttttt)", | |
1680 | SD_BUS_PARAM(images), | |
1681 | method_list_images, | |
1682 | SD_BUS_VTABLE_UNPRIVILEGED), | |
956ecd3c ZJS |
1683 | |
1684 | SD_BUS_SIGNAL_WITH_NAMES("TransferNew", | |
1685 | "uo", | |
1686 | SD_BUS_PARAM(transfer_id) | |
1687 | SD_BUS_PARAM(transfer_path), | |
1688 | 0), | |
1689 | SD_BUS_SIGNAL_WITH_NAMES("TransferRemoved", | |
1690 | "uos", | |
1691 | SD_BUS_PARAM(transfer_id) | |
1692 | SD_BUS_PARAM(transfer_path) | |
1693 | SD_BUS_PARAM(result), | |
1694 | 0), | |
1695 | ||
3d7415f4 LP |
1696 | SD_BUS_VTABLE_END, |
1697 | }; | |
1698 | ||
a3b7cf50 ZJS |
1699 | static const BusObjectImplementation manager_object = { |
1700 | "/org/freedesktop/import1", | |
1701 | "org.freedesktop.import1.Manager", | |
1702 | .vtables = BUS_VTABLES(manager_vtable), | |
1703 | .children = BUS_IMPLEMENTATIONS(&transfer_object), | |
1704 | }; | |
3d7415f4 LP |
1705 | |
1706 | static int manager_add_bus_objects(Manager *m) { | |
1707 | int r; | |
1708 | ||
1709 | assert(m); | |
1710 | ||
a3b7cf50 | 1711 | r = bus_add_implementation(m->bus, &manager_object, m); |
3d7415f4 | 1712 | if (r < 0) |
a3b7cf50 | 1713 | return r; |
3d7415f4 | 1714 | |
ac9f55ed LP |
1715 | r = bus_log_control_api_register(m->bus); |
1716 | if (r < 0) | |
1717 | return r; | |
1718 | ||
0c0b9306 | 1719 | r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.import1", 0, NULL, NULL); |
3d7415f4 | 1720 | if (r < 0) |
0c0b9306 | 1721 | return log_error_errno(r, "Failed to request name: %m"); |
3d7415f4 LP |
1722 | |
1723 | r = sd_bus_attach_event(m->bus, m->event, 0); | |
1724 | if (r < 0) | |
1725 | return log_error_errno(r, "Failed to attach bus to event loop: %m"); | |
1726 | ||
1727 | return 0; | |
1728 | } | |
1729 | ||
1730 | static bool manager_check_idle(void *userdata) { | |
1731 | Manager *m = userdata; | |
1732 | ||
1733 | return hashmap_isempty(m->transfers); | |
1734 | } | |
1735 | ||
c7779a61 IS |
1736 | static void manager_parse_env(Manager *m) { |
1737 | int r; | |
1738 | ||
1739 | assert(m); | |
1740 | ||
1741 | /* Same as src/import/{import,pull}.c: | |
1742 | * Let's make these relatively low-level settings also controllable via env vars. User can then set | |
1743 | * them for systemd-importd.service if they like to tweak behaviour */ | |
1744 | ||
1745 | r = getenv_bool("SYSTEMD_IMPORT_BTRFS_SUBVOL"); | |
1746 | if (r >= 0) | |
1747 | m->use_btrfs_subvol = r; | |
1748 | else if (r != -ENXIO) | |
1749 | log_warning_errno(r, "Failed to parse $SYSTEMD_IMPORT_BTRFS_SUBVOL: %m"); | |
1750 | ||
1751 | r = getenv_bool("SYSTEMD_IMPORT_BTRFS_QUOTA"); | |
1752 | if (r >= 0) | |
1753 | m->use_btrfs_quota = r; | |
1754 | else if (r != -ENXIO) | |
1755 | log_warning_errno(r, "Failed to parse $SYSTEMD_IMPORT_BTRFS_QUOTA: %m"); | |
1756 | } | |
1757 | ||
5272ae42 | 1758 | static int run(int argc, char *argv[]) { |
3d7415f4 LP |
1759 | _cleanup_(manager_unrefp) Manager *m = NULL; |
1760 | int r; | |
1761 | ||
d2acb93d | 1762 | log_setup(); |
3d7415f4 | 1763 | |
fc021a5b ZJS |
1764 | r = service_parse_argv("systemd-importd.service", |
1765 | "VM and container image import and export service.", | |
d4cc0edf ZJS |
1766 | BUS_IMPLEMENTATIONS(&manager_object, |
1767 | &log_control_object), | |
fc021a5b ZJS |
1768 | argc, argv); |
1769 | if (r <= 0) | |
1770 | return r; | |
3d7415f4 | 1771 | |
fc021a5b | 1772 | umask(0022); |
3d7415f4 | 1773 | |
423bba99 | 1774 | assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0); |
3d7415f4 LP |
1775 | |
1776 | r = manager_new(&m); | |
5272ae42 ZJS |
1777 | if (r < 0) |
1778 | return log_error_errno(r, "Failed to allocate manager object: %m"); | |
3d7415f4 | 1779 | |
c7779a61 IS |
1780 | manager_parse_env(m); |
1781 | ||
3d7415f4 LP |
1782 | r = manager_add_bus_objects(m); |
1783 | if (r < 0) | |
5272ae42 | 1784 | return r; |
3d7415f4 | 1785 | |
deb86997 MY |
1786 | r = sd_notify(false, NOTIFY_READY); |
1787 | if (r < 0) | |
1788 | log_warning_errno(r, "Failed to send readiness notification, ignoring: %m"); | |
1789 | ||
1790 | r = bus_event_loop_with_idle( | |
1791 | m->event, | |
1792 | m->bus, | |
1793 | "org.freedesktop.import1", | |
1794 | DEFAULT_EXIT_USEC, | |
1795 | manager_check_idle, | |
1796 | m); | |
5272ae42 ZJS |
1797 | if (r < 0) |
1798 | return log_error_errno(r, "Failed to run event loop: %m"); | |
3d7415f4 | 1799 | |
5272ae42 | 1800 | return 0; |
3d7415f4 | 1801 | } |
5272ae42 ZJS |
1802 | |
1803 | DEFINE_MAIN_FUNCTION(run); |