• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 13935887515

18 Mar 2025 07:10PM UTC coverage: 71.913% (-0.03%) from 71.946%
13935887515

push

github

web-flow
Several fixes and cleanups around sd_listen_fds() (#36788)

15 of 24 new or added lines in 5 files covered. (62.5%)

993 existing lines in 54 files now uncovered.

296157 of 411825 relevant lines covered (71.91%)

710024.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.52
/src/import/importd.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <sys/prctl.h>
4
#include <sys/wait.h>
5

6
#include "sd-bus.h"
7
#include "sd-varlink.h"
8

9
#include "alloc-util.h"
10
#include "build-path.h"
11
#include "bus-common-errors.h"
12
#include "bus-get-properties.h"
13
#include "bus-log-control-api.h"
14
#include "bus-polkit.h"
15
#include "common-signal.h"
16
#include "constants.h"
17
#include "daemon-util.h"
18
#include "discover-image.h"
19
#include "env-util.h"
20
#include "event-util.h"
21
#include "fd-util.h"
22
#include "float.h"
23
#include "hostname-util.h"
24
#include "import-common.h"
25
#include "import-util.h"
26
#include "json-util.h"
27
#include "machine-pool.h"
28
#include "main-func.h"
29
#include "mkdir-label.h"
30
#include "notify-recv.h"
31
#include "os-util.h"
32
#include "parse-util.h"
33
#include "path-util.h"
34
#include "percent-util.h"
35
#include "process-util.h"
36
#include "service-util.h"
37
#include "signal-util.h"
38
#include "socket-util.h"
39
#include "stat-util.h"
40
#include "string-table.h"
41
#include "strv.h"
42
#include "syslog-util.h"
43
#include "user-util.h"
44
#include "varlink-io.systemd.Import.h"
45
#include "varlink-io.systemd.service.h"
46
#include "varlink-util.h"
47
#include "web-util.h"
48

49
typedef struct Transfer Transfer;
50
typedef struct Manager Manager;
51

52
typedef enum TransferType {
53
        TRANSFER_IMPORT_TAR,
54
        TRANSFER_IMPORT_RAW,
55
        TRANSFER_IMPORT_FS,
56
        TRANSFER_EXPORT_TAR,
57
        TRANSFER_EXPORT_RAW,
58
        TRANSFER_PULL_TAR,
59
        TRANSFER_PULL_RAW,
60
        _TRANSFER_TYPE_MAX,
61
        _TRANSFER_TYPE_INVALID = -EINVAL,
62
} TransferType;
63

64
struct Transfer {
65
        Manager *manager;
66

67
        uint32_t id;
68
        char *object_path;
69

70
        TransferType type;
71
        ImportVerify verify;
72

73
        char *remote;
74
        char *local;
75
        char *image_root;
76
        ImageClass class;
77
        ImportFlags flags;
78
        char *format;
79

80
        PidRef pidref;
81

82
        int log_fd;
83

84
        char log_message[LINE_MAX];
85
        size_t log_message_size;
86

87
        sd_event_source *pid_event_source;
88
        sd_event_source *log_event_source;
89

90
        unsigned n_canceled;
91
        unsigned progress_percent;
92
        unsigned progress_percent_sent;
93

94
        int stdin_fd;
95
        int stdout_fd;
96

97
        Set *varlink_subscribed;
98
};
99

100
struct Manager {
101
        sd_event *event;
102
        sd_bus *bus;
103
        sd_varlink_server *varlink_server;
104

105
        uint32_t current_transfer_id;
106
        Hashmap *transfers;
107

108
        Hashmap *polkit_registry;
109

110
        int notify_fd;
111

112
        sd_event_source *notify_event_source;
113

114
        bool use_btrfs_subvol;
115
        bool use_btrfs_quota;
116

117
        RuntimeScope runtime_scope; /* for now: always RUNTIME_SCOPE_SYSTEM */
118
};
119

120
#define TRANSFERS_MAX 64
121

122
static const char* const transfer_type_table[_TRANSFER_TYPE_MAX] = {
123
        [TRANSFER_IMPORT_TAR] = "import-tar",
124
        [TRANSFER_IMPORT_RAW] = "import-raw",
125
        [TRANSFER_IMPORT_FS]  = "import-fs",
126
        [TRANSFER_EXPORT_TAR] = "export-tar",
127
        [TRANSFER_EXPORT_RAW] = "export-raw",
128
        [TRANSFER_PULL_TAR]   = "pull-tar",
129
        [TRANSFER_PULL_RAW]   = "pull-raw",
130
};
131

132
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(transfer_type, TransferType);
×
133

134
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(varlink_hash_ops, void, trivial_hash_func, trivial_compare_func, sd_varlink, sd_varlink_unref);
2✔
135

136
static Transfer *transfer_unref(Transfer *t) {
29✔
137
        if (!t)
29✔
138
                return NULL;
139

140
        if (t->manager)
29✔
141
                hashmap_remove(t->manager->transfers, UINT32_TO_PTR(t->id));
29✔
142

143
        sd_event_source_unref(t->pid_event_source);
29✔
144
        sd_event_source_unref(t->log_event_source);
29✔
145

146
        free(t->remote);
29✔
147
        free(t->local);
29✔
148
        free(t->format);
29✔
149
        free(t->image_root);
29✔
150
        free(t->object_path);
29✔
151

152
        pidref_done_sigkill_wait(&t->pidref);
29✔
153

154
        safe_close(t->log_fd);
29✔
155
        safe_close(t->stdin_fd);
29✔
156
        safe_close(t->stdout_fd);
29✔
157

158
        set_free(t->varlink_subscribed);
29✔
159

160
        return mfree(t);
29✔
161
}
162

163
DEFINE_TRIVIAL_CLEANUP_FUNC(Transfer*, transfer_unref);
58✔
164

165
static int transfer_new(Manager *m, Transfer **ret) {
29✔
166
        _cleanup_(transfer_unrefp) Transfer *t = NULL;
29✔
167
        uint32_t id;
29✔
168
        int r;
29✔
169

170
        assert(m);
29✔
171
        assert(ret);
29✔
172

173
        if (hashmap_size(m->transfers) >= TRANSFERS_MAX)
29✔
174
                return -E2BIG;
175

176
        t = new(Transfer, 1);
29✔
177
        if (!t)
29✔
178
                return -ENOMEM;
179

180
        *t = (Transfer) {
29✔
181
                .type = _TRANSFER_TYPE_INVALID,
182
                .log_fd = -EBADF,
183
                .stdin_fd = -EBADF,
184
                .stdout_fd = -EBADF,
185
                .verify = _IMPORT_VERIFY_INVALID,
186
                .progress_percent = UINT_MAX,
187
                .progress_percent_sent = UINT_MAX,
188
        };
189

190
        id = m->current_transfer_id + 1;
29✔
191

192
        if (asprintf(&t->object_path, "/org/freedesktop/import1/transfer/_%" PRIu32, id) < 0)
29✔
193
                return -ENOMEM;
194

195
        r = hashmap_ensure_put(&m->transfers, &trivial_hash_ops, UINT32_TO_PTR(id), t);
29✔
196
        if (r < 0)
29✔
197
                return r;
198

199
        m->current_transfer_id = id;
29✔
200

201
        t->manager = m;
29✔
202
        t->id = id;
29✔
203

204
        *ret = TAKE_PTR(t);
29✔
205

206
        return 0;
29✔
207
}
208

209
static double transfer_percent_as_double(Transfer *t) {
161✔
210
        assert(t);
161✔
211

212
        if (t->progress_percent == UINT_MAX)
161✔
213
                return -DBL_MAX;
214

215
        return (double) t->progress_percent / 100.0;
161✔
216
}
217

218
static void transfer_send_log_line(Transfer *t, const char *line) {
324✔
219
        int r, priority = LOG_INFO;
324✔
220

221
        assert(t);
324✔
222
        assert(line);
324✔
223

224
        syslog_parse_priority(&line, &priority, true);
324✔
225

226
        log_full(priority, "(transfer%" PRIu32 ") %s", t->id, line);
324✔
227

228
        r = sd_bus_emit_signal(
648✔
229
                        t->manager->bus,
324✔
230
                        t->object_path,
324✔
231
                        "org.freedesktop.import1.Transfer",
232
                        "LogMessage",
233
                        "us",
234
                        priority,
235
                        line);
236
        if (r < 0)
324✔
237
                log_warning_errno(r, "Cannot emit log message bus signal, ignoring: %m");
×
238

239
        r = varlink_many_notifybo(
324✔
240
                        t->varlink_subscribed,
241
                        SD_JSON_BUILD_PAIR("log",
242
                                           SD_JSON_BUILD_OBJECT(
243
                                                           SD_JSON_BUILD_PAIR_UNSIGNED("priority", priority),
244
                                                           SD_JSON_BUILD_PAIR_STRING("message", line))));
245
        if (r < 0)
324✔
246
                log_warning_errno(r, "Cannot emit log message varlink message, ignoring: %m");
×
247
}
324✔
248

249
static void transfer_send_progress_update(Transfer *t) {
161✔
250
        int r;
161✔
251

252
        assert(t);
161✔
253

254
        if (t->progress_percent_sent == t->progress_percent)
161✔
255
                return;
256

257
        double progress = transfer_percent_as_double(t);
161✔
258

259
        r = sd_bus_emit_signal(
322✔
260
                        t->manager->bus,
161✔
261
                        t->object_path,
161✔
262
                        "org.freedesktop.import1.Transfer",
263
                        "ProgressUpdate",
264
                        "d",
265
                        progress);
266
        if (r < 0)
161✔
267
                log_warning_errno(r, "Cannot emit progress update bus signal, ignoring: %m");
×
268

269
        r = varlink_many_notifybo(
161✔
270
                        t->varlink_subscribed,
271
                        SD_JSON_BUILD_PAIR_REAL("progress", progress));
272
        if (r < 0)
161✔
273
                log_warning_errno(r, "Cannot emit progress update varlink message, ignoring: %m");
×
274

275
        t->progress_percent_sent = t->progress_percent;
161✔
276
}
277

278
static void transfer_send_logs(Transfer *t, bool flush) {
252✔
279
        assert(t);
252✔
280

281
        /* Try to send out all log messages, if we can. But if we
282
         * can't we remove the messages from the buffer, but don't
283
         * fail */
284

285
        while (t->log_message_size > 0) {
576✔
286
                _cleanup_free_ char *n = NULL;
324✔
287
                char *e;
324✔
288

289
                if (t->log_message_size >= sizeof(t->log_message))
324✔
290
                        e = t->log_message + sizeof(t->log_message);
2✔
291
                else {
292
                        char *a, *b;
322✔
293

294
                        a = memchr(t->log_message, 0, t->log_message_size);
322✔
295
                        b = memchr(t->log_message, '\n', t->log_message_size);
322✔
296

297
                        if (a && b)
322✔
298
                                e = a < b ? a : b;
×
299
                        else if (a)
322✔
300
                                e = a;
301
                        else
302
                                e = b;
322✔
303
                }
304

305
                if (!e) {
324✔
UNCOV
306
                        if (!flush)
×
307
                                return;
308

309
                        e = t->log_message + t->log_message_size;
×
310
                }
311

312
                n = strndup(t->log_message, e - t->log_message);
324✔
313

314
                /* Skip over NUL and newlines */
315
                while (e < t->log_message + t->log_message_size && IN_SET(*e, 0, '\n'))
646✔
316
                        e++;
322✔
317

318
                memmove(t->log_message, e, t->log_message + sizeof(t->log_message) - e);
324✔
319
                t->log_message_size -= e - t->log_message;
324✔
320

321
                if (!n) {
324✔
322
                        log_oom();
×
323
                        continue;
×
324
                }
325

326
                if (isempty(n))
324✔
327
                        continue;
×
328

329
                transfer_send_log_line(t, n);
324✔
330
        }
331
}
332

333
static int transfer_finalize(Transfer *t, bool success) {
29✔
334
        int r;
29✔
335

336
        assert(t);
29✔
337

338
        transfer_send_logs(t, true);
29✔
339

340
        r = sd_bus_emit_signal(
29✔
341
                        t->manager->bus,
29✔
342
                        "/org/freedesktop/import1",
343
                        "org.freedesktop.import1.Manager",
344
                        "TransferRemoved",
345
                        "uos",
346
                        t->id,
347
                        t->object_path,
348
                        success ? "done" :
349
                        t->n_canceled > 0 ? "canceled" : "failed");
2✔
350
        if (r < 0)
29✔
351
                log_error_errno(r, "Cannot emit message: %m");
×
352

353
        if (success)
29✔
354
                r = varlink_many_reply(t->varlink_subscribed, NULL);
27✔
355
        else if (t->n_canceled > 0)
2✔
356
                r = varlink_many_error(t->varlink_subscribed, "io.systemd.Import.TransferCancelled", NULL);
×
357
        else
358
                r = varlink_many_error(t->varlink_subscribed, "io.systemd.Import.TransferFailed", NULL);
2✔
359
        if (r < 0)
29✔
360
                log_warning_errno(r, "Cannot emit varlink reply, ignoring: %m");
×
361

362
        transfer_unref(t);
29✔
363
        return 0;
29✔
364
}
365

366
static int transfer_cancel(Transfer *t) {
×
367
        int r;
×
368

369
        assert(t);
×
370

371
        r = pidref_kill_and_sigcont(&t->pidref, t->n_canceled < 3 ? SIGTERM : SIGKILL);
×
372
        if (r < 0)
×
373
                return r;
374

375
        t->n_canceled++;
×
376
        return 0;
×
377
}
378

379
static int transfer_on_pid(sd_event_source *s, const siginfo_t *si, void *userdata) {
29✔
380
        Transfer *t = ASSERT_PTR(userdata);
29✔
381
        bool success = false;
29✔
382

383
        assert(s);
29✔
384

385
        if (si->si_code == CLD_EXITED) {
29✔
386
                if (si->si_status != 0)
29✔
387
                        log_error("Transfer process failed with exit code %i.", si->si_status);
2✔
388
                else {
389
                        log_debug("Transfer process succeeded.");
27✔
390
                        success = true;
391
                }
392

393
        } else if (IN_SET(si->si_code, CLD_KILLED, CLD_DUMPED))
×
394
                log_error("Transfer process terminated by signal %s.", signal_to_string(si->si_status));
×
395
        else
396
                log_error("Transfer process failed due to unknown reason.");
×
397

398
        pidref_done(&t->pidref);
29✔
399

400
        return transfer_finalize(t, success);
29✔
401
}
402

403
static int transfer_on_log(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
252✔
404
        Transfer *t = ASSERT_PTR(userdata);
252✔
405
        ssize_t l;
252✔
406

407
        assert(s);
252✔
408

409
        l = read(fd, t->log_message + t->log_message_size, sizeof(t->log_message) - t->log_message_size);
252✔
410
        if (l < 0)
252✔
411
                log_error_errno(errno, "Failed to read log message: %m");
×
412
        if (l <= 0) {
252✔
413
                /* EOF/read error. We just close the pipe here, and
414
                 * close the watch, waiting for the SIGCHLD to arrive,
415
                 * before we do anything else. */
416
                t->log_event_source = sd_event_source_unref(t->log_event_source);
29✔
417
                return 0;
29✔
418
        }
419

420
        t->log_message_size += l;
223✔
421

422
        transfer_send_logs(t, false);
223✔
423

424
        return 0;
223✔
425
}
426

427
static int transfer_start(Transfer *t) {
29✔
428
        _cleanup_close_pair_ int pipefd[2] = EBADF_PAIR;
29✔
429
        int r;
29✔
430

431
        assert(t);
29✔
432
        assert(!pidref_is_set(&t->pidref));
29✔
433

434
        if (pipe2(pipefd, O_CLOEXEC) < 0)
29✔
435
                return -errno;
×
436

437
        r = pidref_safe_fork_full(
116✔
438
                        "(sd-transfer)",
439
                        (int[]) { t->stdin_fd, t->stdout_fd < 0 ? pipefd[1] : t->stdout_fd, pipefd[1] },
29✔
440
                        /* except_fds= */ NULL, /* n_except_fds= */ 0,
441
                        FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_REOPEN_LOG,
442
                        &t->pidref);
443
        if (r < 0)
58✔
444
                return r;
445
        if (r == 0) {
58✔
446
                const char *cmd[] = {
29✔
447
                        NULL, /* systemd-import, systemd-import-fs, systemd-export or systemd-pull */
448
                        NULL, /* tar, raw  */
449
                        NULL, /* --verify= */
450
                        NULL, /* verify argument */
451
                        NULL, /* --class= */
452
                        NULL, /* class argument */
453
                        NULL, /* --keep-download= */
454
                        NULL, /* maybe --force */
455
                        NULL, /* maybe --read-only */
456
                        NULL, /* if so: the actual URL */
457
                        NULL, /* maybe --format= */
458
                        NULL, /* if so: the actual format */
459
                        NULL, /* maybe --image-root= */
460
                        NULL, /* if so: the image root path */
461
                        NULL, /* remote */
462
                        NULL, /* local */
463
                        NULL
464
                };
465
                size_t k = 0;
29✔
466

467
                /* Child */
468

469
                if (setenv("SYSTEMD_LOG_TARGET", "console-prefixed", 1) < 0 ||
58✔
470
                    setenv("NOTIFY_SOCKET", "/run/systemd/import/notify", 1) < 0) {
29✔
471
                        log_error_errno(errno, "setenv() failed: %m");
×
472
                        _exit(EXIT_FAILURE);
×
473
                }
474

475
                r = setenv_systemd_log_level();
29✔
476
                if (r < 0)
29✔
477
                        log_warning_errno(r, "Failed to update $SYSTEMD_LOG_LEVEL, ignoring: %m");
×
478

479
                r = setenv_systemd_exec_pid(true);
29✔
480
                if (r < 0)
29✔
481
                        log_warning_errno(r, "Failed to update $SYSTEMD_EXEC_PID, ignoring: %m");
×
482

483
                switch (t->type) {
29✔
484

485
                case TRANSFER_IMPORT_TAR:
10✔
486
                case TRANSFER_IMPORT_RAW:
487
                        cmd[k++] = SYSTEMD_IMPORT_PATH;
10✔
488
                        break;
10✔
489

490
                case TRANSFER_IMPORT_FS:
3✔
491
                        cmd[k++] = SYSTEMD_IMPORT_FS_PATH;
3✔
492
                        break;
3✔
493

494
                case TRANSFER_EXPORT_TAR:
10✔
495
                case TRANSFER_EXPORT_RAW:
496
                        cmd[k++] = SYSTEMD_EXPORT_PATH;
10✔
497
                        break;
10✔
498

499
                case TRANSFER_PULL_TAR:
6✔
500
                case TRANSFER_PULL_RAW:
501
                        cmd[k++] = SYSTEMD_PULL_PATH;
6✔
502
                        break;
6✔
503

504
                default:
×
505
                        assert_not_reached();
×
506
                }
507

508
                switch (t->type) {
29✔
509

510
                case TRANSFER_IMPORT_TAR:
14✔
511
                case TRANSFER_EXPORT_TAR:
512
                case TRANSFER_PULL_TAR:
513
                        cmd[k++] = "tar";
14✔
514
                        break;
14✔
515

516
                case TRANSFER_IMPORT_RAW:
12✔
517
                case TRANSFER_EXPORT_RAW:
518
                case TRANSFER_PULL_RAW:
519
                        cmd[k++] = "raw";
12✔
520
                        break;
12✔
521

522
                case TRANSFER_IMPORT_FS:
3✔
523
                        cmd[k++] = "run";
3✔
524
                        break;
3✔
525

526
                default:
29✔
527
                        ;
29✔
528
                }
529

530
                if (t->verify != _IMPORT_VERIFY_INVALID) {
29✔
531
                        cmd[k++] = "--verify";
6✔
532
                        cmd[k++] = import_verify_to_string(t->verify);
6✔
533
                }
534

535
                if (t->class != IMAGE_MACHINE) {
29✔
536
                        cmd[k++] = "--class";
12✔
537
                        cmd[k++] = image_class_to_string(t->class);
12✔
538
                }
539

540
                if (IN_SET(t->type, TRANSFER_PULL_TAR, TRANSFER_PULL_RAW))
29✔
541
                        cmd[k++] = FLAGS_SET(t->flags, IMPORT_PULL_KEEP_DOWNLOAD) ?
6✔
542
                                "--keep-download=yes" : "--keep-download=no";
6✔
543

544
                if (FLAGS_SET(t->flags, IMPORT_FORCE))
29✔
545
                        cmd[k++] = "--force";
×
546
                if (FLAGS_SET(t->flags, IMPORT_READ_ONLY))
29✔
547
                        cmd[k++] = "--read-only";
×
548

549
                if (t->format) {
29✔
550
                        cmd[k++] = "--format";
4✔
551
                        cmd[k++] = t->format;
4✔
552
                }
553

554
                if (t->image_root) {
29✔
555
                        cmd[k++] = "--image-root";
1✔
556
                        cmd[k++] = t->image_root;
1✔
557
                }
558

559
                if (!IN_SET(t->type, TRANSFER_EXPORT_TAR, TRANSFER_EXPORT_RAW)) {
29✔
560
                        if (t->remote)
19✔
561
                                cmd[k++] = t->remote;
6✔
562
                        else
563
                                cmd[k++] = "-";
13✔
564
                }
565

566
                if (t->local)
29✔
567
                        cmd[k++] = t->local;
29✔
568
                cmd[k] = NULL;
29✔
569

570
                assert(k < ELEMENTSOF(cmd));
29✔
571

572
                if (DEBUG_LOGGING) {
29✔
573
                        _cleanup_free_ char *joined = strv_join((char**) cmd, " ");
58✔
574
                        log_debug("Calling: %s", strnull(joined));
29✔
575
                }
576

577
                r = invoke_callout_binary(cmd[0], (char * const *) cmd);
29✔
578
                log_error_errno(r, "Failed to execute %s tool: %m", cmd[0]);
×
579
                _exit(EXIT_FAILURE);
×
580
        }
581

582
        pipefd[1] = safe_close(pipefd[1]);
29✔
583
        t->log_fd = TAKE_FD(pipefd[0]);
29✔
584

585
        t->stdin_fd = safe_close(t->stdin_fd);
29✔
586

587
        r = event_add_child_pidref(
58✔
588
                        t->manager->event,
29✔
589
                        &t->pid_event_source,
590
                        &t->pidref,
591
                        WEXITED,
592
                        transfer_on_pid,
593
                        t);
594
        if (r < 0)
29✔
595
                return r;
596

597
        r = sd_event_add_io(t->manager->event, &t->log_event_source,
29✔
598
                            t->log_fd, EPOLLIN, transfer_on_log, t);
599
        if (r < 0)
29✔
600
                return r;
601

602
        /* Make sure always process logging before SIGCHLD */
603
        r = sd_event_source_set_priority(t->log_event_source, SD_EVENT_PRIORITY_NORMAL -5);
29✔
604
        if (r < 0)
29✔
605
                return r;
606

607
        r = sd_bus_emit_signal(
58✔
608
                        t->manager->bus,
29✔
609
                        "/org/freedesktop/import1",
610
                        "org.freedesktop.import1.Manager",
611
                        "TransferNew",
612
                        "uo",
613
                        t->id,
614
                        t->object_path);
615
        if (r < 0)
29✔
616
                return r;
×
617

618
        return 0;
619
}
620

621
static Manager *manager_unref(Manager *m) {
5✔
622
        Transfer *t;
5✔
623

624
        if (!m)
5✔
625
                return NULL;
626

627
        sd_event_source_unref(m->notify_event_source);
5✔
628
        safe_close(m->notify_fd);
5✔
629

630
        while ((t = hashmap_first(m->transfers)))
5✔
631
                transfer_unref(t);
×
632

633
        hashmap_free(m->transfers);
5✔
634

635
        hashmap_free(m->polkit_registry);
5✔
636

637
        m->bus = sd_bus_flush_close_unref(m->bus);
5✔
638
        m->varlink_server = sd_varlink_server_unref(m->varlink_server);
5✔
639

640
        sd_event_unref(m->event);
5✔
641

642
        return mfree(m);
5✔
643
}
644

645
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref);
10✔
646

647
static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
192✔
648
        Manager *m = ASSERT_PTR(userdata);
192✔
649
        int r;
192✔
650

651
        _cleanup_free_ char *buf = NULL;
192✔
652
        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
192✔
653
        r = notify_recv(fd, &buf, /* ret_ucred= */ NULL, &pidref);
192✔
654
        if (r == -EAGAIN)
192✔
655
                return 0;
656
        if (r < 0)
192✔
657
                return r;
658

659
        Transfer *t;
192✔
660
        HASHMAP_FOREACH(t, m->transfers)
192✔
661
                if (pidref_equal(&pidref, &t->pidref))
192✔
662
                        break;
663
        if (!t) {
192✔
664
                log_warning("Got notification datagram from unexpected peer, ignoring.");
×
665
                return 0;
×
666
        }
667

668
        char *p = find_line_startswith(buf, "X_IMPORT_PROGRESS=");
192✔
669
        if (!p)
192✔
670
                return 0;
671

672
        truncate_nl(p);
161✔
673

674
        r = parse_percent(p);
161✔
675
        if (r < 0) {
161✔
676
                log_warning("Got invalid percent value '%s', ignoring.", p);
×
677
                return 0;
×
678
        }
679

680
        t->progress_percent = (unsigned) r;
161✔
681

682
        log_debug("Got percentage from client: %u%%", t->progress_percent);
161✔
683

684
        transfer_send_progress_update(t);
161✔
685
        return 0;
686
}
687

688
static int manager_new(Manager **ret) {
5✔
689
        _cleanup_(manager_unrefp) Manager *m = NULL;
5✔
690
        static const union sockaddr_union sa = {
5✔
691
                .un.sun_family = AF_UNIX,
692
                .un.sun_path = "/run/systemd/import/notify",
693
        };
694
        int r;
5✔
695

696
        assert(ret);
5✔
697

698
        m = new(Manager, 1);
5✔
699
        if (!m)
5✔
700
                return -ENOMEM;
701

702
        *m = (Manager) {
5✔
703
                .use_btrfs_subvol = true,
704
                .use_btrfs_quota = true,
705
                .runtime_scope = RUNTIME_SCOPE_SYSTEM,
706
        };
707

708
        r = sd_event_default(&m->event);
5✔
709
        if (r < 0)
5✔
710
                return r;
711

712
        r = sd_event_set_signal_exit(m->event, true);
5✔
713
        if (r < 0)
5✔
714
                return r;
715

716
        r = sd_event_add_signal(m->event, NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, NULL);
5✔
717
        if (r < 0)
5✔
718
                return r;
719

720
        r = sd_event_add_memory_pressure(m->event, NULL, NULL, NULL);
5✔
721
        if (r < 0)
5✔
722
                log_debug_errno(r, "Failed allocate memory pressure event source, ignoring: %m");
×
723

724
        r = sd_event_set_watchdog(m->event, true);
5✔
725
        if (r < 0)
5✔
726
                log_debug_errno(r, "Failed to enable watchdog logic, ignoring: %m");
×
727

728
        m->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
5✔
729
        if (m->notify_fd < 0)
5✔
730
                return -errno;
×
731

732
        (void) mkdir_parents_label(sa.un.sun_path, 0755);
5✔
733
        (void) sockaddr_un_unlink(&sa.un);
5✔
734

735
        if (bind(m->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
5✔
736
                return -errno;
×
737

738
        r = setsockopt_int(m->notify_fd, SOL_SOCKET, SO_PASSCRED, true);
5✔
739
        if (r < 0)
5✔
740
                return r;
741

742
        r = setsockopt_int(m->notify_fd, SOL_SOCKET, SO_PASSPIDFD, true);
5✔
743
        if (r < 0)
5✔
744
                log_debug_errno(r, "Failed to enable SO_PASSPIDFD on notification socket, ignoring. %m");
×
745

746
        r = sd_event_add_io(m->event, &m->notify_event_source,
5✔
747
                            m->notify_fd, EPOLLIN, manager_on_notify, m);
748
        if (r < 0)
5✔
749
                return r;
750

751
        *ret = TAKE_PTR(m);
5✔
752

753
        return 0;
5✔
754
}
755

756
static Transfer *manager_find(Manager *m, TransferType type, const char *remote) {
6✔
757
        Transfer *t;
6✔
758

759
        assert(m);
6✔
760
        assert(type >= 0);
6✔
761
        assert(type < _TRANSFER_TYPE_MAX);
6✔
762

763
        HASHMAP_FOREACH(t, m->transfers)
6✔
764
                if (t->type == type && streq_ptr(t->remote, remote))
×
765
                        return t;
×
766

767
        return NULL;
6✔
768
}
769

770
static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
10✔
771
        _cleanup_(transfer_unrefp) Transfer *t = NULL;
10✔
772
        ImageClass class = _IMAGE_CLASS_INVALID;
10✔
773
        Manager *m = ASSERT_PTR(userdata);
10✔
774
        const char *local;
10✔
775
        TransferType type;
10✔
776
        struct stat st;
10✔
777
        uint64_t flags;
10✔
778
        int fd, r;
10✔
779

780
        assert(msg);
10✔
781

782
        r = bus_verify_polkit_async(
10✔
783
                        msg,
784
                        "org.freedesktop.import1.import",
785
                        /* details= */ NULL,
786
                        &m->polkit_registry,
787
                        error);
788
        if (r < 0)
10✔
789
                return r;
790
        if (r == 0)
10✔
791
                return 1; /* Will call us back */
792

793
        if (endswith(sd_bus_message_get_member(msg), "Ex")) {
10✔
794
                const char *sclass;
10✔
795

796
                r = sd_bus_message_read(msg, "hsst", &fd, &local, &sclass, &flags);
10✔
797
                if (r < 0)
10✔
798
                        return r;
×
799

800
                class = image_class_from_string(sclass);
10✔
801
                if (class < 0)
10✔
802
                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
803
                                                 "Image class '%s' not known", sclass);
804

805
                if (flags & ~(IMPORT_READ_ONLY|IMPORT_FORCE))
10✔
806
                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
807
                                                 "Flags 0x%" PRIx64 " invalid", flags);
808
        } else {
809
                int force, read_only;
×
810

811
                r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only);
×
812
                if (r < 0)
×
813
                        return r;
×
814

815
                class = IMAGE_MACHINE;
×
816

817
                flags = 0;
×
818
                SET_FLAG(flags, IMPORT_FORCE, force);
×
819
                SET_FLAG(flags, IMPORT_READ_ONLY, read_only);
×
820
        }
821

822
        r = fd_verify_safe_flags(fd);
10✔
823
        if (r < 0)
10✔
824
                return r;
825

826
        if (fstat(fd, &st) < 0)
10✔
827
                return -errno;
×
828

829
        if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode))
10✔
830
                return -EINVAL;
831

832
        if (!image_name_is_valid(local))
10✔
833
                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
834
                                         "Local image name %s is invalid", local);
835

836
        if (class == IMAGE_MACHINE) {
10✔
837
                r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota);
7✔
838
                if (r < 0)
7✔
839
                        return r;
840
        }
841

842
        type = startswith(sd_bus_message_get_member(msg), "ImportTar") ?
10✔
843
                TRANSFER_IMPORT_TAR : TRANSFER_IMPORT_RAW;
10✔
844

845
        r = transfer_new(m, &t);
10✔
846
        if (r < 0)
10✔
847
                return r;
848

849
        t->type = type;
10✔
850
        t->class = class;
10✔
851
        t->flags = flags;
10✔
852

853
        t->local = strdup(local);
10✔
854
        if (!t->local)
10✔
855
                return -ENOMEM;
856

857
        t->stdin_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
10✔
858
        if (t->stdin_fd < 0)
10✔
859
                return -errno;
×
860

861
        r = transfer_start(t);
10✔
862
        if (r < 0)
10✔
863
                return r;
864

865
        r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path);
10✔
866
        if (r < 0)
10✔
867
                return r;
868

869
        TAKE_PTR(t);
10✔
870
        return 1;
10✔
871
}
872

873
static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
3✔
874
        _cleanup_(transfer_unrefp) Transfer *t = NULL;
3✔
875
        ImageClass class = _IMAGE_CLASS_INVALID;
3✔
876
        Manager *m = ASSERT_PTR(userdata);
3✔
877
        const char *local;
3✔
878
        uint64_t flags;
3✔
879
        int fd, r;
3✔
880

881
        assert(msg);
3✔
882

883
        r = bus_verify_polkit_async(
3✔
884
                        msg,
885
                        "org.freedesktop.import1.import",
886
                        /* details= */ NULL,
887
                        &m->polkit_registry,
888
                        error);
889
        if (r < 0)
3✔
890
                return r;
891
        if (r == 0)
3✔
892
                return 1; /* Will call us back */
893

894
        if (endswith(sd_bus_message_get_member(msg), "Ex")) {
3✔
895
                const char *sclass;
3✔
896

897
                r = sd_bus_message_read(msg, "hsst", &fd, &local, &sclass, &flags);
3✔
898
                if (r < 0)
3✔
899
                        return r;
×
900

901
                class = image_class_from_string(sclass);
3✔
902
                if (class < 0)
3✔
903
                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
904
                                                 "Image class '%s' not known", sclass);
905

906
                if (flags & ~(IMPORT_READ_ONLY|IMPORT_FORCE))
3✔
907
                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
908
                                                 "Flags 0x%" PRIx64 " invalid", flags);
909
        } else {
910
                int force, read_only;
×
911

912
                r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only);
×
913
                if (r < 0)
×
914
                        return r;
×
915

916
                class = IMAGE_MACHINE;
×
917

918
                flags = 0;
×
919
                SET_FLAG(flags, IMPORT_FORCE, force);
×
920
                SET_FLAG(flags, IMPORT_READ_ONLY, read_only);
×
921
        }
922

923
        r = fd_verify_safe_flags_full(fd, O_DIRECTORY);
3✔
924
        if (r < 0)
3✔
925
                return r;
926

927
        r = fd_verify_directory(fd);
3✔
928
        if (r < 0)
3✔
929
                return r;
930

931
        if (!image_name_is_valid(local))
3✔
932
                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
933
                                         "Local image name %s is invalid", local);
934

935
        if (class == IMAGE_MACHINE) {
3✔
936
                r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota);
2✔
937
                if (r < 0)
2✔
938
                        return r;
939
        }
940

941
        r = transfer_new(m, &t);
3✔
942
        if (r < 0)
3✔
943
                return r;
944

945
        t->type = TRANSFER_IMPORT_FS;
3✔
946
        t->class = class;
3✔
947
        t->flags = flags;
3✔
948

949
        t->local = strdup(local);
3✔
950
        if (!t->local)
3✔
951
                return -ENOMEM;
952

953
        t->stdin_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
3✔
954
        if (t->stdin_fd < 0)
3✔
955
                return -errno;
×
956

957
        r = transfer_start(t);
3✔
958
        if (r < 0)
3✔
959
                return r;
960

961
        r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path);
3✔
962
        if (r < 0)
3✔
963
                return r;
964

965
        TAKE_PTR(t);
3✔
966
        return 1;
3✔
967
}
968

969
static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
10✔
970
        _cleanup_(transfer_unrefp) Transfer *t = NULL;
10✔
971
        ImageClass class = _IMAGE_CLASS_INVALID;
10✔
972
        Manager *m = ASSERT_PTR(userdata);
10✔
973
        const char *local, *format;
10✔
974
        TransferType type;
10✔
975
        uint64_t flags;
10✔
976
        struct stat st;
10✔
977
        int fd, r;
10✔
978

979
        assert(msg);
10✔
980

981
        r = bus_verify_polkit_async(
10✔
982
                        msg,
983
                        "org.freedesktop.import1.export",
984
                        /* details= */ NULL,
985
                        &m->polkit_registry,
986
                        error);
987
        if (r < 0)
10✔
988
                return r;
989
        if (r == 0)
10✔
990
                return 1; /* Will call us back */
991

992
        if (endswith(sd_bus_message_get_member(msg), "Ex")) {
10✔
993
                const char *sclass;
10✔
994

995
                r = sd_bus_message_read(msg, "sshst", &local, &sclass, &fd, &format, &flags);
10✔
996
                if (r < 0)
10✔
997
                        return r;
×
998

999
                class = image_class_from_string(sclass);
10✔
1000
                if (class < 0)
10✔
1001
                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
1002
                                                 "Image class '%s' not known", sclass);
1003

1004
                if (flags != 0)
10✔
1005
                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
1006
                                                 "Flags 0x%" PRIx64 " invalid", flags);
1007
        } else {
1008
                r = sd_bus_message_read(msg, "shs", &local, &fd, &format);
×
1009
                if (r < 0)
×
1010
                        return r;
1011

1012
                class = IMAGE_MACHINE;
×
1013
                flags = 0;
×
1014
        }
1015

1016
        if (!image_name_is_valid(local))
10✔
1017
                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
1018
                                         "Local image name %s is invalid", local);
1019

1020
        r = fd_verify_safe_flags(fd);
10✔
1021
        if (r < 0)
10✔
1022
                return r;
1023

1024
        if (fstat(fd, &st) < 0)
10✔
1025
                return -errno;
×
1026

1027
        if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode))
10✔
1028
                return -EINVAL;
1029

1030
        type = startswith(sd_bus_message_get_member(msg), "ExportTar") ?
10✔
1031
                TRANSFER_EXPORT_TAR : TRANSFER_EXPORT_RAW;
10✔
1032

1033
        r = transfer_new(m, &t);
10✔
1034
        if (r < 0)
10✔
1035
                return r;
1036

1037
        t->type = type;
10✔
1038
        t->class = class;
10✔
1039
        t->flags = flags;
10✔
1040

1041
        if (!isempty(format)) {
10✔
1042
                t->format = strdup(format);
4✔
1043
                if (!t->format)
4✔
1044
                        return -ENOMEM;
1045
        }
1046

1047
        t->local = strdup(local);
10✔
1048
        if (!t->local)
10✔
1049
                return -ENOMEM;
1050

1051
        t->stdout_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
10✔
1052
        if (t->stdout_fd < 0)
10✔
1053
                return -errno;
×
1054

1055
        r = transfer_start(t);
10✔
1056
        if (r < 0)
10✔
1057
                return r;
1058

1059
        r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path);
10✔
1060
        if (r < 0)
10✔
1061
                return r;
1062

1063
        TAKE_PTR(t);
10✔
1064
        return 1;
10✔
1065
}
1066

1067
static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
4✔
1068
        _cleanup_(transfer_unrefp) Transfer *t = NULL;
4✔
1069
        ImageClass class = _IMAGE_CLASS_INVALID;
4✔
1070
        const char *remote, *local, *verify;
4✔
1071
        Manager *m = ASSERT_PTR(userdata);
4✔
1072
        TransferType type;
4✔
1073
        uint64_t flags;
4✔
1074
        ImportVerify v;
4✔
1075
        int r;
4✔
1076

1077
        assert(msg);
4✔
1078

1079
        r = bus_verify_polkit_async(
4✔
1080
                        msg,
1081
                        "org.freedesktop.import1.pull",
1082
                        /* details= */ NULL,
1083
                        &m->polkit_registry,
1084
                        error);
1085
        if (r < 0)
4✔
1086
                return r;
1087
        if (r == 0)
4✔
1088
                return 1; /* Will call us back */
1089

1090
        if (endswith(sd_bus_message_get_member(msg), "Ex")) {
4✔
1091
                const char *sclass;
4✔
1092

1093
                r = sd_bus_message_read(msg, "sssst", &remote, &local, &sclass, &verify, &flags);
4✔
1094
                if (r < 0)
4✔
1095
                        return r;
×
1096

1097
                class = image_class_from_string(sclass);
4✔
1098
                if (class < 0)
4✔
1099
                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
1100
                                                 "Image class '%s' not known", sclass);
1101

1102
                if (flags & ~(IMPORT_FORCE|IMPORT_READ_ONLY|IMPORT_PULL_KEEP_DOWNLOAD))
4✔
1103
                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
1104
                                                 "Flags 0x%" PRIx64 " invalid", flags);
1105
        } else {
1106
                int force;
×
1107

1108
                r = sd_bus_message_read(msg, "sssb", &remote, &local, &verify, &force);
×
1109
                if (r < 0)
×
1110
                        return r;
×
1111

1112
                class = IMAGE_MACHINE;
×
1113

1114
                flags = 0;
×
1115
                SET_FLAG(flags, IMPORT_FORCE, force);
×
1116
        }
1117

1118
        if (!http_url_is_valid(remote) && !file_url_is_valid(remote))
4✔
1119
                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
1120
                                         "URL %s is invalid", remote);
1121

1122
        if (isempty(local))
4✔
1123
                local = NULL;
×
1124
        else if (!image_name_is_valid(local))
4✔
1125
                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
1126
                                         "Local image name %s is invalid", local);
1127

1128
        if (isempty(verify))
4✔
1129
                v = IMPORT_VERIFY_SIGNATURE;
1130
        else
1131
                v = import_verify_from_string(verify);
4✔
1132
        if (v < 0)
4✔
1133
                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
1134
                                         "Unknown verification mode %s", verify);
1135

1136
        if (class == IMAGE_MACHINE) {
4✔
1137
                r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota);
×
1138
                if (r < 0)
×
1139
                        return r;
1140
        }
1141

1142
        type = startswith(sd_bus_message_get_member(msg), "PullTar") ?
4✔
1143
                TRANSFER_PULL_TAR : TRANSFER_PULL_RAW;
4✔
1144

1145
        if (manager_find(m, type, remote))
4✔
1146
                return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS,
×
1147
                                         "Transfer for %s already in progress.", remote);
1148

1149
        r = transfer_new(m, &t);
4✔
1150
        if (r < 0)
4✔
1151
                return r;
1152

1153
        t->type = type;
4✔
1154
        t->verify = v;
4✔
1155
        t->flags = flags;
4✔
1156
        t->class = class;
4✔
1157

1158
        t->remote = strdup(remote);
4✔
1159
        if (!t->remote)
4✔
1160
                return -ENOMEM;
1161

1162
        if (local) {
4✔
1163
                t->local = strdup(local);
4✔
1164
                if (!t->local)
4✔
1165
                        return -ENOMEM;
1166
        }
1167

1168
        r = transfer_start(t);
4✔
1169
        if (r < 0)
4✔
1170
                return r;
1171

1172
        r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path);
4✔
1173
        if (r < 0)
4✔
1174
                return r;
1175

1176
        TAKE_PTR(t);
4✔
1177
        return 1;
4✔
1178
}
1179

1180
static int method_list_transfers(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
4✔
1181
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
4✔
1182
        Manager *m = ASSERT_PTR(userdata);
4✔
1183
        ImageClass class = _IMAGE_CLASS_INVALID;
4✔
1184
        Transfer *t;
4✔
1185
        int r;
4✔
1186

1187
        assert(msg);
4✔
1188

1189
        bool ex = endswith(sd_bus_message_get_member(msg), "Ex");
4✔
1190
        if (ex) {
4✔
1191
                const char *sclass;
4✔
1192
                uint64_t flags;
4✔
1193

1194
                r = sd_bus_message_read(msg, "st", &sclass, &flags);
4✔
1195
                if (r < 0)
4✔
1196
                        return bus_log_parse_error(r);
×
1197

1198
                if (!isempty(sclass)) {
4✔
1199
                        class = image_class_from_string(sclass);
×
1200
                        if (class < 0)
×
1201
                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
1202
                                                         "Image class '%s' not known", sclass);
1203
                }
1204

1205
                if (flags != 0)
4✔
1206
                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
1207
                                                 "Flags 0x%" PRIx64 " invalid", flags);
1208
        }
1209

1210
        r = sd_bus_message_new_method_return(msg, &reply);
4✔
1211
        if (r < 0)
4✔
1212
                return r;
1213

1214
        if (ex)
4✔
1215
                r = sd_bus_message_open_container(reply, 'a', "(ussssdo)");
4✔
1216
        else
1217
                r = sd_bus_message_open_container(reply, 'a', "(usssdo)");
×
1218
        if (r < 0)
4✔
1219
                return r;
1220

1221
        HASHMAP_FOREACH(t, m->transfers) {
4✔
1222

1223
                if (class >= 0 && class != t->class)
×
1224
                        continue;
×
1225

1226
                if (ex)
×
1227
                        r = sd_bus_message_append(
×
1228
                                        reply,
1229
                                        "(ussssdo)",
1230
                                        t->id,
1231
                                        transfer_type_to_string(t->type),
1232
                                        t->remote,
1233
                                        t->local,
1234
                                        image_class_to_string(t->class),
×
1235
                                        transfer_percent_as_double(t),
1236
                                        t->object_path);
×
1237
                else
1238
                        r = sd_bus_message_append(
×
1239
                                        reply,
1240
                                        "(usssdo)",
1241
                                        t->id,
1242
                                        transfer_type_to_string(t->type),
1243
                                        t->remote,
1244
                                        t->local,
×
1245
                                        transfer_percent_as_double(t),
1246
                                        t->object_path);
×
1247
                if (r < 0)
×
1248
                        return r;
×
1249
        }
1250

1251
        r = sd_bus_message_close_container(reply);
4✔
1252
        if (r < 0)
4✔
1253
                return r;
1254

1255
        return sd_bus_send(NULL, reply, NULL);
4✔
1256
}
1257

1258
static int method_cancel(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
×
1259
        Transfer *t = ASSERT_PTR(userdata);
×
1260
        int r;
×
1261

1262
        assert(msg);
×
1263

1264
        r = bus_verify_polkit_async(
×
1265
                        msg,
1266
                        "org.freedesktop.import1.pull",
1267
                        /* details= */ NULL,
1268
                        &t->manager->polkit_registry,
×
1269
                        error);
1270
        if (r < 0)
×
1271
                return r;
1272
        if (r == 0)
×
1273
                return 1; /* Will call us back */
1274

1275
        r = transfer_cancel(t);
×
1276
        if (r < 0)
×
1277
                return r;
1278

1279
        return sd_bus_reply_method_return(msg, NULL);
×
1280
}
1281

1282
static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
1✔
1283
        Manager *m = ASSERT_PTR(userdata);
1✔
1284
        Transfer *t;
1✔
1285
        uint32_t id;
1✔
1286
        int r;
1✔
1287

1288
        assert(msg);
1✔
1289

1290
        r = bus_verify_polkit_async(
1✔
1291
                        msg,
1292
                        "org.freedesktop.import1.cancel",
1293
                        /* details= */ NULL,
1294
                        &m->polkit_registry,
1295
                        error);
1296
        if (r < 0)
1✔
1297
                return r;
1✔
1298
        if (r == 0)
1✔
1299
                return 1; /* Will call us back */
1300

1301
        r = sd_bus_message_read(msg, "u", &id);
1✔
1302
        if (r < 0)
1✔
1303
                return r;
1304
        if (id <= 0)
1✔
1305
                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid transfer id");
×
1306

1307
        t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
1✔
1308
        if (!t)
1✔
1309
                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_TRANSFER, "No transfer by id %" PRIu32, id);
1✔
1310

1311
        r = transfer_cancel(t);
×
1312
        if (r < 0)
×
1313
                return r;
1314

1315
        return sd_bus_reply_method_return(msg, NULL);
×
1316
}
1317

1318
static int method_list_images(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
5✔
1319
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
5✔
1320
        ImageClass class = _IMAGE_CLASS_INVALID;
5✔
1321
        Manager *m = ASSERT_PTR(userdata);
5✔
1322
        int r;
5✔
1323

1324
        assert(msg);
5✔
1325

1326
        const char *sclass;
5✔
1327
        uint64_t flags;
5✔
1328

1329
        r = sd_bus_message_read(msg, "st", &sclass, &flags);
5✔
1330
        if (r < 0)
5✔
1331
                return r;
1332

1333
        if (!isempty(sclass)) {
5✔
1334
                class = image_class_from_string(sclass);
×
1335
                if (class < 0)
×
1336
                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
1337
                                                 "Image class '%s' not known", sclass);
1338
        }
1339

1340
        if (flags != 0)
5✔
1341
                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
×
1342
                                         "Flags 0x%" PRIx64 " invalid", flags);
1343

1344
        r = sd_bus_message_new_method_return(msg, &reply);
5✔
1345
        if (r < 0)
5✔
1346
                return r;
1347

1348
        r = sd_bus_message_open_container(reply, 'a', "(ssssbtttttt)");
5✔
1349
        if (r < 0)
5✔
1350
                return r;
1351

1352
        for (ImageClass c = class < 0 ? 0 : class;
5✔
1353
             class < 0 ? (c < _IMAGE_CLASS_MAX) : (c == class);
25✔
1354
             c++) {
20✔
1355

1356
                _cleanup_hashmap_free_ Hashmap *h = NULL;
20✔
1357

1358
                h = hashmap_new(&image_hash_ops);
20✔
1359
                if (!h)
20✔
1360
                        return -ENOMEM;
1361

1362
                r = image_discover(m->runtime_scope, c, /* root= */ NULL, h);
20✔
1363
                if (r < 0) {
20✔
1364
                        if (class >= 0)
×
1365
                                return r;
1366

1367
                        log_warning_errno(r, "Failed to discover images of type %s: %m", image_class_to_string(c));
×
1368
                        continue;
×
1369
                }
1370

1371
                Image *i;
20✔
1372
                HASHMAP_FOREACH(i, h) {
37✔
1373
                        r = sd_bus_message_append(
17✔
1374
                                        reply,
1375
                                        "(ssssbtttttt)",
1376
                                        image_class_to_string(i->class),
1377
                                        i->name,
1378
                                        image_type_to_string(i->type),
1379
                                        i->path,
1380
                                        i->read_only,
17✔
1381
                                        i->crtime,
1382
                                        i->mtime,
1383
                                        i->usage,
1384
                                        i->usage_exclusive,
1385
                                        i->limit,
1386
                                        i->limit_exclusive);
17✔
1387
                        if (r < 0)
17✔
1388
                                return r;
×
1389
                }
1390
        }
1391

1392
        r = sd_bus_message_close_container(reply);
5✔
1393
        if (r < 0)
5✔
1394
                return r;
1395

1396
        return sd_bus_send(NULL, reply, NULL);
5✔
1397
}
1398

1399
static int property_get_progress(
×
1400
                sd_bus *bus,
1401
                const char *path,
1402
                const char *interface,
1403
                const char *property,
1404
                sd_bus_message *reply,
1405
                void *userdata,
1406
                sd_bus_error *error) {
1407

1408
        Transfer *t = ASSERT_PTR(userdata);
×
1409

1410
        assert(bus);
×
1411
        assert(reply);
×
1412

1413
        return sd_bus_message_append(reply, "d", transfer_percent_as_double(t));
×
1414
}
1415

1416
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, transfer_type, TransferType);
×
1417
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_verify, import_verify, ImportVerify);
×
1418

1419
static int transfer_object_find(
×
1420
                sd_bus *bus,
1421
                const char *path,
1422
                const char *interface,
1423
                void *userdata,
1424
                void **found,
1425
                sd_bus_error *error) {
1426

1427
        Manager *m = ASSERT_PTR(userdata);
×
1428
        Transfer *t;
×
1429
        const char *p;
×
1430
        uint32_t id;
×
1431
        int r;
×
1432

1433
        assert(bus);
×
1434
        assert(path);
×
1435
        assert(interface);
×
1436
        assert(found);
×
1437

1438
        p = startswith(path, "/org/freedesktop/import1/transfer/_");
×
1439
        if (!p)
×
1440
                return 0;
×
1441

1442
        r = safe_atou32(p, &id);
×
1443
        if (r < 0 || id == 0)
×
1444
                return 0;
1445

1446
        t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
×
1447
        if (!t)
×
1448
                return 0;
1449

1450
        *found = t;
×
1451
        return 1;
×
1452
}
1453

1454
static int transfer_node_enumerator(
×
1455
                sd_bus *bus,
1456
                const char *path,
1457
                void *userdata,
1458
                char ***nodes,
1459
                sd_bus_error *error) {
1460

1461
        _cleanup_strv_free_ char **l = NULL;
×
1462
        Manager *m = userdata;
×
1463
        Transfer *t;
×
1464
        unsigned k = 0;
×
1465

1466
        l = new0(char*, hashmap_size(m->transfers) + 1);
×
1467
        if (!l)
×
1468
                return -ENOMEM;
1469

1470
        HASHMAP_FOREACH(t, m->transfers) {
×
1471

1472
                l[k] = strdup(t->object_path);
×
1473
                if (!l[k])
×
1474
                        return -ENOMEM;
×
1475

1476
                k++;
×
1477
        }
1478

1479
        *nodes = TAKE_PTR(l);
×
1480

1481
        return 1;
×
1482
}
1483

1484
static const sd_bus_vtable transfer_vtable[] = {
1485
        SD_BUS_VTABLE_START(0),
1486

1487
        SD_BUS_PROPERTY("Id", "u", NULL, offsetof(Transfer, id), SD_BUS_VTABLE_PROPERTY_CONST),
1488
        SD_BUS_PROPERTY("Local", "s", NULL, offsetof(Transfer, local), SD_BUS_VTABLE_PROPERTY_CONST),
1489
        SD_BUS_PROPERTY("Remote", "s", NULL, offsetof(Transfer, remote), SD_BUS_VTABLE_PROPERTY_CONST),
1490
        SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Transfer, type), SD_BUS_VTABLE_PROPERTY_CONST),
1491
        SD_BUS_PROPERTY("Verify", "s", property_get_verify, offsetof(Transfer, verify), SD_BUS_VTABLE_PROPERTY_CONST),
1492
        SD_BUS_PROPERTY("Progress", "d", property_get_progress, 0, 0),
1493

1494
        SD_BUS_METHOD("Cancel", NULL, NULL, method_cancel, SD_BUS_VTABLE_UNPRIVILEGED),
1495

1496
        SD_BUS_SIGNAL_WITH_NAMES("LogMessage",
1497
                                 "us",
1498
                                 SD_BUS_PARAM(priority)
1499
                                 SD_BUS_PARAM(line),
1500
                                 0),
1501
        SD_BUS_SIGNAL_WITH_NAMES("ProgressUpdate",
1502
                                 "d",
1503
                                 SD_BUS_PARAM(progress),
1504
                                 0),
1505

1506
        SD_BUS_VTABLE_END,
1507
};
1508

1509
static const BusObjectImplementation transfer_object = {
1510
        "/org/freedesktop/import1/transfer",
1511
        "org.freedesktop.import1.Transfer",
1512
        .fallback_vtables = BUS_FALLBACK_VTABLES({transfer_vtable, transfer_object_find}),
1513
        .node_enumerator = transfer_node_enumerator,
1514
};
1515

1516
static const sd_bus_vtable manager_vtable[] = {
1517
        SD_BUS_VTABLE_START(0),
1518

1519
        SD_BUS_METHOD_WITH_NAMES("ImportTar",
1520
                                 "hsbb",
1521
                                 SD_BUS_PARAM(fd)
1522
                                 SD_BUS_PARAM(local_name)
1523
                                 SD_BUS_PARAM(force)
1524
                                 SD_BUS_PARAM(read_only),
1525
                                 "uo",
1526
                                 SD_BUS_PARAM(transfer_id)
1527
                                 SD_BUS_PARAM(transfer_path),
1528
                                 method_import_tar_or_raw,
1529
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1530
        SD_BUS_METHOD_WITH_NAMES("ImportTarEx",
1531
                                 "hsst",
1532
                                 SD_BUS_PARAM(fd)
1533
                                 SD_BUS_PARAM(local_name)
1534
                                 SD_BUS_PARAM(class)
1535
                                 SD_BUS_PARAM(flags),
1536
                                 "uo",
1537
                                 SD_BUS_PARAM(transfer_id)
1538
                                 SD_BUS_PARAM(transfer_path),
1539
                                 method_import_tar_or_raw,
1540
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1541
        SD_BUS_METHOD_WITH_NAMES("ImportRaw",
1542
                                 "hsbb",
1543
                                 SD_BUS_PARAM(fd)
1544
                                 SD_BUS_PARAM(local_name)
1545
                                 SD_BUS_PARAM(force)
1546
                                 SD_BUS_PARAM(read_only),
1547
                                 "uo",
1548
                                 SD_BUS_PARAM(transfer_id)
1549
                                 SD_BUS_PARAM(transfer_path),
1550
                                 method_import_tar_or_raw,
1551
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1552
        SD_BUS_METHOD_WITH_NAMES("ImportRawEx",
1553
                                 "hsst",
1554
                                 SD_BUS_PARAM(fd)
1555
                                 SD_BUS_PARAM(local_name)
1556
                                 SD_BUS_PARAM(class)
1557
                                 SD_BUS_PARAM(flags),
1558
                                 "uo",
1559
                                 SD_BUS_PARAM(transfer_id)
1560
                                 SD_BUS_PARAM(transfer_path),
1561
                                 method_import_tar_or_raw,
1562
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1563
        SD_BUS_METHOD_WITH_NAMES("ImportFileSystem",
1564
                                 "hsbb",
1565
                                 SD_BUS_PARAM(fd)
1566
                                 SD_BUS_PARAM(local_name)
1567
                                 SD_BUS_PARAM(force)
1568
                                 SD_BUS_PARAM(read_only),
1569
                                 "uo",
1570
                                 SD_BUS_PARAM(transfer_id)
1571
                                 SD_BUS_PARAM(transfer_path),
1572
                                 method_import_fs,
1573
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1574
        SD_BUS_METHOD_WITH_NAMES("ImportFileSystemEx",
1575
                                 "hsst",
1576
                                 SD_BUS_PARAM(fd)
1577
                                 SD_BUS_PARAM(local_name)
1578
                                 SD_BUS_PARAM(class)
1579
                                 SD_BUS_PARAM(flags),
1580
                                 "uo",
1581
                                 SD_BUS_PARAM(transfer_id)
1582
                                 SD_BUS_PARAM(transfer_path),
1583
                                 method_import_fs,
1584
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1585
        SD_BUS_METHOD_WITH_NAMES("ExportTar",
1586
                                 "shs",
1587
                                 SD_BUS_PARAM(local_name)
1588
                                 SD_BUS_PARAM(fd)
1589
                                 SD_BUS_PARAM(format),
1590
                                 "uo",
1591
                                 SD_BUS_PARAM(transfer_id)
1592
                                 SD_BUS_PARAM(transfer_path),
1593
                                 method_export_tar_or_raw,
1594
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1595
        SD_BUS_METHOD_WITH_NAMES("ExportTarEx",
1596
                                 "sshst",
1597
                                 SD_BUS_PARAM(local_name)
1598
                                 SD_BUS_PARAM(class)
1599
                                 SD_BUS_PARAM(fd)
1600
                                 SD_BUS_PARAM(format)
1601
                                 SD_BUS_PARAM(flags),
1602
                                 "uo",
1603
                                 SD_BUS_PARAM(transfer_id)
1604
                                 SD_BUS_PARAM(transfer_path),
1605
                                 method_export_tar_or_raw,
1606
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1607
        SD_BUS_METHOD_WITH_NAMES("ExportRaw",
1608
                                 "shs",
1609
                                 SD_BUS_PARAM(local_name)
1610
                                 SD_BUS_PARAM(fd)
1611
                                 SD_BUS_PARAM(format),
1612
                                 "uo",
1613
                                 SD_BUS_PARAM(transfer_id)
1614
                                 SD_BUS_PARAM(transfer_path),
1615
                                 method_export_tar_or_raw,
1616
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1617
        SD_BUS_METHOD_WITH_NAMES("ExportRawEx",
1618
                                 "sshst",
1619
                                 SD_BUS_PARAM(local_name)
1620
                                 SD_BUS_PARAM(class)
1621
                                 SD_BUS_PARAM(fd)
1622
                                 SD_BUS_PARAM(format)
1623
                                 SD_BUS_PARAM(flags),
1624
                                 "uo",
1625
                                 SD_BUS_PARAM(transfer_id)
1626
                                 SD_BUS_PARAM(transfer_path),
1627
                                 method_export_tar_or_raw,
1628
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1629
        SD_BUS_METHOD_WITH_NAMES("PullTar",
1630
                                 "sssb",
1631
                                 SD_BUS_PARAM(url)
1632
                                 SD_BUS_PARAM(local_name)
1633
                                 SD_BUS_PARAM(verify_mode)
1634
                                 SD_BUS_PARAM(force),
1635
                                 "uo",
1636
                                 SD_BUS_PARAM(transfer_id)
1637
                                 SD_BUS_PARAM(transfer_path),
1638
                                 method_pull_tar_or_raw,
1639
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1640
        SD_BUS_METHOD_WITH_NAMES("PullTarEx",
1641
                                 "sssst",
1642
                                 SD_BUS_PARAM(url)
1643
                                 SD_BUS_PARAM(local_name)
1644
                                 SD_BUS_PARAM(class)
1645
                                 SD_BUS_PARAM(verify_mode)
1646
                                 SD_BUS_PARAM(flags),
1647
                                 "uo",
1648
                                 SD_BUS_PARAM(transfer_id)
1649
                                 SD_BUS_PARAM(transfer_path),
1650
                                 method_pull_tar_or_raw,
1651
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1652
        SD_BUS_METHOD_WITH_NAMES("PullRaw",
1653
                                 "sssb",
1654
                                 SD_BUS_PARAM(url)
1655
                                 SD_BUS_PARAM(local_name)
1656
                                 SD_BUS_PARAM(verify_mode)
1657
                                 SD_BUS_PARAM(force),
1658
                                 "uo",
1659
                                 SD_BUS_PARAM(transfer_id)
1660
                                 SD_BUS_PARAM(transfer_path),
1661
                                 method_pull_tar_or_raw,
1662
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1663
        SD_BUS_METHOD_WITH_NAMES("PullRawEx",
1664
                                 "sssst",
1665
                                 SD_BUS_PARAM(url)
1666
                                 SD_BUS_PARAM(local_name)
1667
                                 SD_BUS_PARAM(class)
1668
                                 SD_BUS_PARAM(verify_mode)
1669
                                 SD_BUS_PARAM(flags),
1670
                                 "uo",
1671
                                 SD_BUS_PARAM(transfer_id)
1672
                                 SD_BUS_PARAM(transfer_path),
1673
                                 method_pull_tar_or_raw,
1674
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1675
        SD_BUS_METHOD_WITH_NAMES("ListTransfers",
1676
                                 NULL,,
1677
                                 "a(usssdo)",
1678
                                 SD_BUS_PARAM(transfers),
1679
                                 method_list_transfers,
1680
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1681
        SD_BUS_METHOD_WITH_NAMES("ListTransfersEx",
1682
                                 "st",
1683
                                 SD_BUS_PARAM(class)
1684
                                 SD_BUS_PARAM(flags),
1685
                                 "a(ussssdo)",
1686
                                 SD_BUS_PARAM(transfers),
1687
                                 method_list_transfers,
1688
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1689
        SD_BUS_METHOD_WITH_NAMES("CancelTransfer",
1690
                                 "u",
1691
                                 SD_BUS_PARAM(transfer_id),
1692
                                 NULL,,
1693
                                 method_cancel_transfer,
1694
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1695
        SD_BUS_METHOD_WITH_NAMES("ListImages",
1696
                                 "st",
1697
                                 SD_BUS_PARAM(class)
1698
                                 SD_BUS_PARAM(flags),
1699
                                 "a(ssssbtttttt)",
1700
                                 SD_BUS_PARAM(images),
1701
                                 method_list_images,
1702
                                 SD_BUS_VTABLE_UNPRIVILEGED),
1703

1704
        SD_BUS_SIGNAL_WITH_NAMES("TransferNew",
1705
                                 "uo",
1706
                                 SD_BUS_PARAM(transfer_id)
1707
                                 SD_BUS_PARAM(transfer_path),
1708
                                 0),
1709
        SD_BUS_SIGNAL_WITH_NAMES("TransferRemoved",
1710
                                 "uos",
1711
                                 SD_BUS_PARAM(transfer_id)
1712
                                 SD_BUS_PARAM(transfer_path)
1713
                                 SD_BUS_PARAM(result),
1714
                                 0),
1715

1716
        SD_BUS_VTABLE_END,
1717
};
1718

1719
static const BusObjectImplementation manager_object = {
1720
        "/org/freedesktop/import1",
1721
        "org.freedesktop.import1.Manager",
1722
        .vtables = BUS_VTABLES(manager_vtable),
1723
        .children = BUS_IMPLEMENTATIONS(&transfer_object),
1724
};
1725

1726
static int manager_connect_bus(Manager *m) {
5✔
1727
        int r;
5✔
1728

1729
        assert(m);
5✔
1730
        assert(m->event);
5✔
1731
        assert(!m->bus);
5✔
1732

1733
        r = bus_open_system_watch_bind(&m->bus);
5✔
1734
        if (r < 0)
5✔
1735
                return log_error_errno(r, "Failed to get system bus connection: %m");
×
1736

1737
        r = bus_add_implementation(m->bus, &manager_object, m);
5✔
1738
        if (r < 0)
5✔
1739
                return r;
1740

1741
        r = bus_log_control_api_register(m->bus);
5✔
1742
        if (r < 0)
5✔
1743
                return r;
1744

1745
        r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.import1", 0, NULL, NULL);
5✔
1746
        if (r < 0)
5✔
1747
                return log_error_errno(r, "Failed to request name: %m");
×
1748

1749
        r = sd_bus_attach_event(m->bus, m->event, 0);
5✔
1750
        if (r < 0)
5✔
1751
                return log_error_errno(r, "Failed to attach bus to event loop: %m");
×
1752

1753
        return 0;
1754
}
1755

1756
static JSON_DISPATCH_ENUM_DEFINE(json_dispatch_image_class, ImageClass, image_class_from_string);
2✔
1757

1758
static int make_transfer_json(Transfer *t, sd_json_variant **ret) {
×
1759
        int r;
×
1760

1761
        assert(t);
×
1762

1763
        r = sd_json_buildo(ret,
×
1764
                           SD_JSON_BUILD_PAIR("id", SD_JSON_BUILD_UNSIGNED(t->id)),
1765
                           SD_JSON_BUILD_PAIR("type", JSON_BUILD_STRING_UNDERSCORIFY(transfer_type_to_string(t->type))),
1766
                           SD_JSON_BUILD_PAIR("remote", SD_JSON_BUILD_STRING(t->remote)),
1767
                           SD_JSON_BUILD_PAIR("local", SD_JSON_BUILD_STRING(t->local)),
1768
                           SD_JSON_BUILD_PAIR("class", JSON_BUILD_STRING_UNDERSCORIFY(image_class_to_string(t->class))),
1769
                           SD_JSON_BUILD_PAIR("percent", SD_JSON_BUILD_REAL(transfer_percent_as_double(t))));
1770
        if (r < 0)
×
1771
                return log_error_errno(r, "Failed to build transfer JSON data: %m");
×
1772

1773
        return 0;
1774
}
1775

1776
static int vl_method_list_transfers(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
1✔
1777

1778
        struct p {
1✔
1779
                ImageClass class;
1780
        } p = {
1✔
1781
                .class = _IMAGE_CLASS_INVALID,
1782
        };
1783

1784
        static const sd_json_dispatch_field dispatch_table[] = {
1✔
1785
                { "class", SD_JSON_VARIANT_STRING, json_dispatch_image_class, offsetof(struct p, class), 0 },
1786
                {},
1787
        };
1788

1789
        Manager *m = ASSERT_PTR(userdata);
1✔
1790
        int r;
1✔
1791

1792
        assert(link);
1✔
1793
        assert(parameters);
1✔
1794

1795
        r = sd_varlink_dispatch(link, parameters, dispatch_table, &p);
1✔
1796
        if (r != 0)
1✔
1797
                return r;
1✔
1798

1799
        if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
1✔
1800
                return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
×
1801

1802
        Transfer *previous = NULL, *t;
1✔
1803
        HASHMAP_FOREACH(t, m->transfers) {
1✔
1804

1805
                if (p.class >= 0 && p.class != t->class)
×
1806
                        continue;
×
1807

1808
                if (previous) {
×
1809
                        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
×
1810

1811
                        r = make_transfer_json(previous, &v);
×
1812
                        if (r < 0)
×
1813
                                return r;
1814

1815
                        r = sd_varlink_notify(link, v);
×
1816
                        if (r < 0)
×
1817
                                return r;
1818
                }
1819

1820
                previous = t;
×
1821
        }
1822

1823
        if (previous) {
1✔
1824
                _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
×
1825

1826
                r = make_transfer_json(previous, &v);
×
1827
                if (r < 0)
×
1828
                        return r;
1829

1830
                return sd_varlink_reply(link, v);
×
1831
        }
1832

1833
        return sd_varlink_error(link, "io.systemd.Import.NoTransfers", NULL);
1✔
1834
}
1835

1836
static JSON_DISPATCH_ENUM_DEFINE(json_dispatch_import_verify, ImportVerify, import_verify_from_string);
2✔
1837
static JSON_DISPATCH_ENUM_DEFINE(json_dispatch_import_type, ImportType, import_type_from_string);
2✔
1838

1839
static int vl_method_pull(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
2✔
1840

1841
        struct p {
2✔
1842
                const char *remote, *local;
1843
                ImageClass class;
1844
                ImportType type;
1845
                ImportVerify verify;
1846
                bool force;
1847
                bool read_only;
1848
                bool keep_download;
1849
                const char *image_root;
1850
        } p = {
2✔
1851
                .class = _IMAGE_CLASS_INVALID,
1852
                .verify = IMPORT_VERIFY_SIGNATURE,
1853
        };
1854

1855
        static const sd_json_dispatch_field dispatch_table[] = {
2✔
1856
                { "remote",       SD_JSON_VARIANT_STRING,  sd_json_dispatch_const_string, offsetof(struct p, remote),        SD_JSON_MANDATORY },
1857
                { "local",        SD_JSON_VARIANT_STRING,  sd_json_dispatch_const_string, offsetof(struct p, local),         0                 },
1858
                { "class",        SD_JSON_VARIANT_STRING,  json_dispatch_image_class,     offsetof(struct p, class),         SD_JSON_MANDATORY },
1859
                { "type",         SD_JSON_VARIANT_STRING,  json_dispatch_import_type,     offsetof(struct p, type),          SD_JSON_MANDATORY },
1860
                { "verify",       SD_JSON_VARIANT_STRING,  json_dispatch_import_verify,   offsetof(struct p, verify),        SD_JSON_STRICT    },
1861
                { "force",        SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool,      offsetof(struct p, force),         0                 },
1862
                { "readOnly",     SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool,      offsetof(struct p, read_only),     0                 },
1863
                { "keepDownload", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool,      offsetof(struct p, keep_download), 0                 },
1864
                { "imageRoot",    SD_JSON_VARIANT_STRING,  json_dispatch_const_path,      offsetof(struct p, image_root),    SD_JSON_STRICT    },
1865
                VARLINK_DISPATCH_POLKIT_FIELD,
1866
                {},
1867
        };
1868

1869
        Manager *m = ASSERT_PTR(userdata);
2✔
1870
        int r;
2✔
1871

1872
        assert(link);
2✔
1873
        assert(parameters);
2✔
1874

1875
        r = sd_varlink_dispatch(link, parameters, dispatch_table, &p);
2✔
1876
        if (r != 0)
2✔
1877
                return r;
2✔
1878

1879
        if (!http_url_is_valid(p.remote) && !file_url_is_valid(p.remote))
2✔
1880
                return sd_varlink_error_invalid_parameter_name(link, "remote");
×
1881

1882
        if (p.local && !image_name_is_valid(p.local))
2✔
1883
                return sd_varlink_error_invalid_parameter_name(link, "local");
×
1884

1885
        uint64_t transfer_flags = (p.force * IMPORT_FORCE) | (p.read_only * IMPORT_READ_ONLY) | (p.keep_download * IMPORT_PULL_KEEP_DOWNLOAD);
2✔
1886

1887
        TransferType tt =
4✔
1888
                p.type == IMPORT_TAR ? TRANSFER_PULL_TAR :
2✔
1889
                p.type == IMPORT_RAW ? TRANSFER_PULL_RAW : _TRANSFER_TYPE_INVALID;
×
1890

1891
        assert(tt >= 0);
×
1892

1893
        if (manager_find(m, tt, p.remote))
2✔
1894
                return sd_varlink_errorbo(link, "io.systemd.Import.AlreadyInProgress", SD_JSON_BUILD_PAIR_STRING("remote", p.remote));
×
1895

1896
        r = varlink_verify_polkit_async(
6✔
1897
                        link,
1898
                        m->bus,
1899
                        "org.freedesktop.import1.pull",
1900
                        (const char**) STRV_MAKE(
2✔
1901
                                        "remote", p.remote,
1902
                                        "local",  p.local,
1903
                                        "class",  image_class_to_string(p.class),
1904
                                        "type",   import_type_to_string(p.type),
1905
                                        "verify", import_verify_to_string(p.verify)),
1906
                        &m->polkit_registry);
1907
        if (r <= 0)
2✔
1908
                return r;
1909

1910
        _cleanup_(transfer_unrefp) Transfer *t = NULL;
2✔
1911

1912
        r = transfer_new(m, &t);
2✔
1913
        if (r < 0)
2✔
1914
                return r;
1915

1916
        t->type = tt;
2✔
1917
        t->verify = p.verify;
2✔
1918
        t->flags = transfer_flags;
2✔
1919
        t->class = p.class;
2✔
1920

1921
        t->remote = strdup(p.remote);
2✔
1922
        if (!t->remote)
2✔
1923
                return -ENOMEM;
1924

1925
        if (p.local) {
2✔
1926
                t->local = strdup(p.local);
2✔
1927
                if (!t->local)
2✔
1928
                        return -ENOMEM;
1929
        }
1930

1931
        if (p.image_root) {
2✔
1932
                t->image_root = strdup(p.image_root);
1✔
1933
                if (!t->image_root)
1✔
1934
                        return -ENOMEM;
1935
        }
1936

1937
        r = transfer_start(t);
2✔
1938
        if (r < 0)
2✔
1939
                return r;
1940

1941
        /* If more was not set, just return the download id, and be done with it */
1942
        if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
2✔
1943
                return sd_varlink_replybo(link, SD_JSON_BUILD_PAIR("id", SD_JSON_BUILD_UNSIGNED(t->id)));
×
1944

1945
        /* Otherwise add this connection to the set of subscriptions, return the id, but keep the thing running */
1946
        r = set_ensure_put(&t->varlink_subscribed, &varlink_hash_ops, link);
2✔
1947
        if (r < 0)
2✔
1948
                return r;
1949

1950
        sd_varlink_ref(link);
2✔
1951

1952
        r = sd_varlink_notifybo(link, SD_JSON_BUILD_PAIR("id", SD_JSON_BUILD_UNSIGNED(t->id)));
2✔
1953
        if (r < 0)
2✔
1954
                return r;
1955

1956
        TAKE_PTR(t);
2✔
1957
        return 0;
2✔
1958
}
1959

1960
static int manager_connect_varlink(Manager *m) {
5✔
1961
        int r;
5✔
1962

1963
        assert(m);
5✔
1964
        assert(m->event);
5✔
1965
        assert(!m->varlink_server);
5✔
1966

1967
        r = varlink_server_new(&m->varlink_server,
5✔
1968
                               SD_VARLINK_SERVER_ACCOUNT_UID|SD_VARLINK_SERVER_INHERIT_USERDATA,
1969
                               m);
1970
        if (r < 0)
5✔
1971
                return log_error_errno(r, "Failed to allocate varlink server object: %m");
×
1972

1973
        r = sd_varlink_server_add_interface_many(
5✔
1974
                        m->varlink_server,
1975
                        &vl_interface_io_systemd_Import,
1976
                        &vl_interface_io_systemd_service);
1977
        if (r < 0)
5✔
1978
                return log_error_errno(r, "Failed to add Import interface to varlink server: %m");
×
1979

1980
        r = sd_varlink_server_bind_method_many(
5✔
1981
                        m->varlink_server,
1982
                        "io.systemd.Import.ListTransfers",   vl_method_list_transfers,
1983
                        "io.systemd.Import.Pull",            vl_method_pull,
1984
                        "io.systemd.service.Ping",           varlink_method_ping,
1985
                        "io.systemd.service.SetLogLevel",    varlink_method_set_log_level,
1986
                        "io.systemd.service.GetEnvironment", varlink_method_get_environment);
1987
        if (r < 0)
5✔
1988
                return log_error_errno(r, "Failed to bind Varlink method calls: %m");
×
1989

1990
        r = sd_varlink_server_attach_event(m->varlink_server, m->event, SD_EVENT_PRIORITY_NORMAL);
5✔
1991
        if (r < 0)
5✔
1992
                return log_error_errno(r, "Failed to attach Varlink server to event loop: %m");
×
1993

1994
        r = sd_varlink_server_listen_auto(m->varlink_server);
5✔
1995
        if (r < 0)
5✔
1996
                return log_error_errno(r, "Failed to bind to passed Varlink sockets: %m");
×
1997
        if (r == 0) {
5✔
1998
                r = sd_varlink_server_listen_address(m->varlink_server, "/run/systemd/io.systemd.Import", 0666);
×
1999
                if (r < 0)
×
2000
                        return log_error_errno(r, "Failed to bind to Varlink socket: %m");
×
2001
        }
2002

2003
        return 0;
2004
}
2005

2006
static bool manager_check_idle(void *userdata) {
806✔
2007
        Manager *m = ASSERT_PTR(userdata);
806✔
2008

2009
        return hashmap_isempty(m->transfers) &&
806✔
2010
                hashmap_isempty(m->polkit_registry) &&
1,119✔
2011
                sd_varlink_server_current_connections(m->varlink_server) == 0;
313✔
2012
}
2013

2014
static void manager_parse_env(Manager *m) {
5✔
2015
        int r;
5✔
2016

2017
        assert(m);
5✔
2018

2019
        /* Same as src/import/{import,pull}.c:
2020
         * Let's make these relatively low-level settings also controllable via env vars. User can then set
2021
         * them for systemd-importd.service if they like to tweak behaviour */
2022

2023
        r = getenv_bool("SYSTEMD_IMPORT_BTRFS_SUBVOL");
5✔
2024
        if (r >= 0)
5✔
2025
                m->use_btrfs_subvol = r;
×
2026
        else if (r != -ENXIO)
5✔
2027
                log_warning_errno(r, "Failed to parse $SYSTEMD_IMPORT_BTRFS_SUBVOL: %m");
×
2028

2029
        r = getenv_bool("SYSTEMD_IMPORT_BTRFS_QUOTA");
5✔
2030
        if (r >= 0)
5✔
2031
                m->use_btrfs_quota = r;
×
2032
        else if (r != -ENXIO)
5✔
2033
                log_warning_errno(r, "Failed to parse $SYSTEMD_IMPORT_BTRFS_QUOTA: %m");
×
2034
}
5✔
2035

2036
static int run(int argc, char *argv[]) {
5✔
2037
        _cleanup_(manager_unrefp) Manager *m = NULL;
5✔
2038
        int r;
5✔
2039

2040
        log_setup();
5✔
2041

2042
        r = service_parse_argv("systemd-importd.service",
10✔
2043
                               "VM and container image import and export service.",
2044
                               BUS_IMPLEMENTATIONS(&manager_object,
5✔
2045
                                                   &log_control_object),
2046
                               argc, argv);
2047
        if (r <= 0)
5✔
2048
                return r;
2049

2050
        umask(0022);
5✔
2051

2052
        assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
5✔
2053

2054
        r = manager_new(&m);
5✔
2055
        if (r < 0)
5✔
2056
                return log_error_errno(r, "Failed to allocate manager object: %m");
×
2057

2058
        manager_parse_env(m);
5✔
2059

2060
        r = manager_connect_bus(m);
5✔
2061
        if (r < 0)
5✔
2062
                return r;
2063

2064
        r = manager_connect_varlink(m);
5✔
2065
        if (r < 0)
5✔
2066
                return r;
2067

2068
        r = sd_notify(false, NOTIFY_READY);
5✔
2069
        if (r < 0)
5✔
2070
                log_warning_errno(r, "Failed to send readiness notification, ignoring: %m");
×
2071

2072
        r = bus_event_loop_with_idle(
5✔
2073
                        m->event,
2074
                        m->bus,
2075
                        "org.freedesktop.import1",
2076
                        DEFAULT_EXIT_USEC,
2077
                        manager_check_idle,
2078
                        m);
2079
        if (r < 0)
5✔
2080
                return log_error_errno(r, "Failed to run event loop: %m");
×
2081

2082
        return 0;
2083
}
2084

2085
DEFINE_MAIN_FUNCTION(run);
10✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc