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

systemd / systemd / 18765396043

23 Oct 2025 01:51PM UTC coverage: 72.284% (-0.01%) from 72.295%
18765396043

push

github

YHNdnzj
core: increment start limit counter only when we can start the unit

Otherwise, e.g. requesting to start a unit that is under stopping may
enter the failed state.

This makes
- rename .can_start() -> .test_startable(), and make it allow to return
  boolean and refuse to start units when it returns false,
- refuse earlier to start units that are in the deactivating state, so
  several redundant conditions in .start() can be dropped,
- move checks for unit states mapped to UNIT_ACTIVATING from .start() to
  .test_startable().

Fixes #39247.

13 of 15 new or added lines in 8 files covered. (86.67%)

6946 existing lines in 72 files now uncovered.

304970 of 421905 relevant lines covered (72.28%)

1105466.04 hits per line

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

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

3
#include <getopt.h>
4
#include <locale.h>
5
#include <stdio.h>
6

7
#include "sd-event.h"
8

9
#include "alloc-util.h"
10
#include "ansi-color.h"
11
#include "build.h"
12
#include "discover-image.h"
13
#include "env-util.h"
14
#include "hexdecoct.h"
15
#include "import-common.h"
16
#include "import-util.h"
17
#include "io-util.h"
18
#include "log.h"
19
#include "main-func.h"
20
#include "parse-argument.h"
21
#include "parse-util.h"
22
#include "path-util.h"
23
#include "pull-raw.h"
24
#include "pull-tar.h"
25
#include "runtime-scope.h"
26
#include "signal-util.h"
27
#include "string-util.h"
28
#include "verbs.h"
29
#include "web-util.h"
30

31
static char *arg_image_root = NULL;
32
static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
33
static ImportFlags arg_import_flags = IMPORT_PULL_SETTINGS | IMPORT_PULL_ROOTHASH | IMPORT_PULL_ROOTHASH_SIGNATURE | IMPORT_PULL_VERITY | IMPORT_BTRFS_SUBVOL | IMPORT_BTRFS_QUOTA | IMPORT_CONVERT_QCOW2 | IMPORT_SYNC;
34
static uint64_t arg_offset = UINT64_MAX, arg_size_max = UINT64_MAX;
35
static char *arg_checksum = NULL;
36
static ImageClass arg_class = IMAGE_MACHINE;
37
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
38

39
STATIC_DESTRUCTOR_REGISTER(arg_checksum, freep);
26✔
40
STATIC_DESTRUCTOR_REGISTER(arg_image_root, freep);
26✔
41

42
static int normalize_local(const char *local, const char *url, char **ret) {
26✔
43
        _cleanup_free_ char *ll = NULL;
26✔
44
        int r;
26✔
45

46
        if (arg_import_flags & IMPORT_DIRECT) {
26✔
47

48
                if (!local)
20✔
49
                        log_debug("Writing downloaded data to STDOUT.");
12✔
50
                else {
51
                        if (!path_is_absolute(local)) {
8✔
52
                                ll = path_join(arg_image_root, local);
×
53
                                if (!ll)
×
UNCOV
54
                                        return log_oom();
×
55

56
                                local = ll;
57
                        }
58

59
                        if (!path_is_valid(local))
8✔
UNCOV
60
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
61
                                               "Local path name '%s' is not valid.", local);
62
                }
63

64
        } else if (local) {
6✔
65

66
                if (!image_name_is_valid(local))
6✔
UNCOV
67
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
68
                                               "Local image name '%s' is not valid.",
69
                                               local);
70

71
                if (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) {
6✔
72
                        r = image_find(arg_runtime_scope, arg_class, local, NULL, NULL);
6✔
73
                        if (r < 0) {
6✔
74
                                if (r != -ENOENT)
5✔
UNCOV
75
                                        return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
×
76
                        } else
77
                                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
1✔
78
                                                       "Image '%s' already exists.",
79
                                                       local);
80
                }
81
        }
82

83
        if (!ll && local) {
25✔
84
                ll = strdup(local);
13✔
85
                if (!ll)
13✔
UNCOV
86
                        return log_oom();
×
87
        }
88

89
        if (ll) {
12✔
90
                if (arg_offset != UINT64_MAX)
13✔
91
                        log_info("Pulling '%s', saving at offset %" PRIu64 " in '%s'.", url, arg_offset, ll);
4✔
92
                else
93
                        log_info("Pulling '%s', saving as '%s'.", url, ll);
9✔
94
        } else
95
                log_info("Pulling '%s'.", url);
12✔
96

97
        if (!FLAGS_SET(arg_import_flags, IMPORT_DIRECT))
25✔
98
                log_info("Operating on image directory '%s'.", arg_image_root);
5✔
99

100
        if (!FLAGS_SET(arg_import_flags, IMPORT_SYNC))
25✔
UNCOV
101
                log_info("File system synchronization on completion is off.");
×
102

103
        *ret = TAKE_PTR(ll);
25✔
104
        return 0;
25✔
105
}
106

107
static void on_tar_finished(TarPull *pull, int error, void *userdata) {
8✔
108
        sd_event *event = userdata;
8✔
109
        assert(pull);
8✔
110

111
        if (error == 0)
8✔
112
                log_info("Operation completed successfully.");
7✔
113

114
        sd_event_exit(event, ABS(error));
8✔
115
}
8✔
116

117
static int pull_tar(int argc, char *argv[], void *userdata) {
8✔
118
        _cleanup_free_ char *ll = NULL, *normalized = NULL;
8✔
119
        _cleanup_(sd_event_unrefp) sd_event *event = NULL;
8✔
120
        _cleanup_(tar_pull_unrefp) TarPull *pull = NULL;
8✔
121
        const char *url, *local;
8✔
122
        int r;
8✔
123

124
        url = argv[1];
8✔
125
        if (!http_url_is_valid(url) && !file_url_is_valid(url))
8✔
UNCOV
126
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "URL '%s' is not valid.", url);
×
127

128
        if (argc >= 3)
8✔
129
                local = empty_or_dash_to_null(argv[2]);
8✔
130
        else {
UNCOV
131
                _cleanup_free_ char *l = NULL;
×
132

133
                r = import_url_last_component(url, &l);
×
134
                if (r < 0)
×
UNCOV
135
                        return log_error_errno(r, "Failed to get final component of URL: %m");
×
136

137
                r = tar_strip_suffixes(l, &ll);
×
138
                if (r < 0)
×
UNCOV
139
                        return log_oom();
×
140

UNCOV
141
                local = ll;
×
142
        }
143

144
        if (!local && FLAGS_SET(arg_import_flags, IMPORT_DIRECT))
8✔
UNCOV
145
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Pulling tar images to STDOUT is not supported.");
×
146

147
        r = normalize_local(local, url, &normalized);
8✔
148
        if (r < 0)
8✔
149
                return r;
150

151
        r = import_allocate_event_with_signals(&event);
8✔
152
        if (r < 0)
8✔
153
                return r;
154

155
        r = tar_pull_new(&pull, event, arg_image_root, on_tar_finished, event);
8✔
156
        if (r < 0)
8✔
UNCOV
157
                return log_error_errno(r, "Failed to allocate puller: %m");
×
158

159
        r = tar_pull_start(
16✔
160
                        pull,
161
                        url,
162
                        normalized,
163
                        arg_import_flags & IMPORT_PULL_FLAGS_MASK_TAR,
8✔
164
                        arg_verify,
165
                        arg_checksum);
166
        if (r < 0)
8✔
UNCOV
167
                return log_error_errno(r, "Failed to pull image: %m");
×
168

169
        r = sd_event_loop(event);
8✔
170
        if (r < 0)
8✔
UNCOV
171
                return log_error_errno(r, "Failed to run event loop: %m");
×
172

173
        log_info("Exiting.");
8✔
174
        return -r;
8✔
175
}
176

177
static void on_raw_finished(RawPull *pull, int error, void *userdata) {
17✔
178
        sd_event *event = userdata;
17✔
179
        assert(pull);
17✔
180

181
        if (error == 0)
17✔
182
                log_info("Operation completed successfully.");
17✔
183

184
        sd_event_exit(event, ABS(error));
17✔
185
}
17✔
186

187
static int pull_raw(int argc, char *argv[], void *userdata) {
18✔
188
        _cleanup_free_ char *ll = NULL, *normalized = NULL;
18✔
189
        _cleanup_(sd_event_unrefp) sd_event *event = NULL;
18✔
190
        _cleanup_(raw_pull_unrefp) RawPull *pull = NULL;
18✔
191
        const char *url, *local;
18✔
192
        int r;
18✔
193

194
        url = argv[1];
18✔
195
        if (!http_url_is_valid(url) && !file_url_is_valid(url))
18✔
UNCOV
196
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "URL '%s' is not valid.", url);
×
197

198
        if (argc >= 3)
18✔
199
                local = empty_or_dash_to_null(argv[2]);
30✔
200
        else {
UNCOV
201
                _cleanup_free_ char *l = NULL;
×
202

203
                r = import_url_last_component(url, &l);
×
204
                if (r < 0)
×
UNCOV
205
                        return log_error_errno(r, "Failed to get final component of URL: %m");
×
206

207
                r = raw_strip_suffixes(l, &ll);
×
208
                if (r < 0)
×
UNCOV
209
                        return log_oom();
×
210

UNCOV
211
                local = ll;
×
212
        }
213

214
        r = normalize_local(local, url, &normalized);
18✔
215
        if (r < 0)
18✔
216
                return r;
217

218
        r = import_allocate_event_with_signals(&event);
17✔
219
        if (r < 0)
17✔
220
                return r;
221

222
        r = raw_pull_new(&pull, event, arg_image_root, on_raw_finished, event);
17✔
223
        if (r < 0)
17✔
UNCOV
224
                return log_error_errno(r, "Failed to allocate puller: %m");
×
225

226
        r = raw_pull_start(
34✔
227
                        pull,
228
                        url,
229
                        normalized,
230
                        arg_offset,
231
                        arg_size_max,
232
                        arg_import_flags & IMPORT_PULL_FLAGS_MASK_RAW,
17✔
233
                        arg_verify,
234
                        arg_checksum);
235
        if (r < 0)
17✔
UNCOV
236
                return log_error_errno(r, "Failed to pull image: %m");
×
237

238
        r = sd_event_loop(event);
17✔
239
        if (r < 0)
17✔
UNCOV
240
                return log_error_errno(r, "Failed to run event loop: %m");
×
241

242
        log_info("Exiting.");
17✔
243
        return -r;
17✔
244
}
245

UNCOV
246
static int help(int argc, char *argv[], void *userdata) {
×
247

UNCOV
248
        printf("%1$s [OPTIONS...] {COMMAND} ...\n"
×
249
               "\n%4$sDownload disk images.%5$s\n"
250
               "\n%2$sCommands:%3$s\n"
251
               "  tar URL [NAME]              Download a TAR image\n"
252
               "  raw URL [NAME]              Download a RAW image\n"
253
               "\n%2$sOptions:%3$s\n"
254
               "  -h --help                   Show this help\n"
255
               "     --version                Show package version\n"
256
               "     --force                  Force creation of image\n"
257
               "     --verify=MODE            Verify downloaded image, one of: 'no',\n"
258
               "                              'checksum', 'signature' or literal SHA256 hash\n"
259
               "     --settings=BOOL          Download settings file with image\n"
260
               "     --roothash=BOOL          Download root hash file with image\n"
261
               "     --roothash-signature=BOOL\n"
262
               "                              Download root hash signature file with image\n"
263
               "     --verity=BOOL            Download verity file with image\n"
264
               "     --image-root=PATH        Image root directory\n"
265
               "     --read-only              Create a read-only image\n"
266
               "     --direct                 Download directly to specified file\n"
267
               "     --btrfs-subvol=BOOL      Controls whether to create a btrfs subvolume\n"
268
               "                              instead of a directory\n"
269
               "     --btrfs-quota=BOOL       Controls whether to set up quota for btrfs\n"
270
               "                              subvolume\n"
271
               "     --convert-qcow2=BOOL     Controls whether to convert QCOW2 images to\n"
272
               "                              regular disk images\n"
273
               "     --sync=BOOL              Controls whether to sync() before completing\n"
274
               "     --offset=BYTES           Offset to seek to in destination\n"
275
               "     --size-max=BYTES         Maximum number of bytes to write to destination\n"
276
               "     --class=CLASS            Select image class (machine, sysext, confext,\n"
277
               "                              portable)\n"
278
               "     --keep-download=BOOL     Keep a copy pristine copy of the downloaded file\n"
279
               "                              around\n"
280
               "     --system                 Operate in per-system mode\n"
281
               "     --user                   Operate in per-user mode\n",
282
               program_invocation_short_name,
283
               ansi_underline(),
284
               ansi_normal(),
285
               ansi_highlight(),
286
               ansi_normal());
287

UNCOV
288
        return 0;
×
289
}
290

291
static int parse_argv(int argc, char *argv[]) {
26✔
292

293
        enum {
26✔
294
                ARG_VERSION = 0x100,
295
                ARG_FORCE,
296
                ARG_IMAGE_ROOT,
297
                ARG_VERIFY,
298
                ARG_SETTINGS,
299
                ARG_ROOTHASH,
300
                ARG_ROOTHASH_SIGNATURE,
301
                ARG_VERITY,
302
                ARG_READ_ONLY,
303
                ARG_DIRECT,
304
                ARG_BTRFS_SUBVOL,
305
                ARG_BTRFS_QUOTA,
306
                ARG_CONVERT_QCOW2,
307
                ARG_SYNC,
308
                ARG_OFFSET,
309
                ARG_SIZE_MAX,
310
                ARG_CLASS,
311
                ARG_KEEP_DOWNLOAD,
312
                ARG_SYSTEM,
313
                ARG_USER,
314
        };
315

316
        static const struct option options[] = {
26✔
317
                { "help",               no_argument,       NULL, 'h'                    },
318
                { "version",            no_argument,       NULL, ARG_VERSION            },
319
                { "force",              no_argument,       NULL, ARG_FORCE              },
320
                { "image-root",         required_argument, NULL, ARG_IMAGE_ROOT         },
321
                { "verify",             required_argument, NULL, ARG_VERIFY             },
322
                { "settings",           required_argument, NULL, ARG_SETTINGS           },
323
                { "roothash",           required_argument, NULL, ARG_ROOTHASH           },
324
                { "roothash-signature", required_argument, NULL, ARG_ROOTHASH_SIGNATURE },
325
                { "verity",             required_argument, NULL, ARG_VERITY             },
326
                { "read-only",          no_argument,       NULL, ARG_READ_ONLY          },
327
                { "direct",             no_argument,       NULL, ARG_DIRECT             },
328
                { "btrfs-subvol",       required_argument, NULL, ARG_BTRFS_SUBVOL       },
329
                { "btrfs-quota",        required_argument, NULL, ARG_BTRFS_QUOTA        },
330
                { "convert-qcow2",      required_argument, NULL, ARG_CONVERT_QCOW2      },
331
                { "sync",               required_argument, NULL, ARG_SYNC               },
332
                { "offset",             required_argument, NULL, ARG_OFFSET             },
333
                { "size-max",           required_argument, NULL, ARG_SIZE_MAX           },
334
                { "class",              required_argument, NULL, ARG_CLASS              },
335
                { "keep-download",      required_argument, NULL, ARG_KEEP_DOWNLOAD      },
336
                { "system",             no_argument,       NULL, ARG_SYSTEM             },
337
                { "user",               no_argument,       NULL, ARG_USER               },
338
                {}
339
        };
340

341
        int c, r;
26✔
342
        bool auto_settings = true, auto_keep_download = true;
26✔
343

344
        assert(argc >= 0);
26✔
345
        assert(argv);
26✔
346

347
        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
111✔
348

349
                switch (c) {
85✔
350

351
                case 'h':
×
352
                        return help(0, NULL, NULL);
×
353

UNCOV
354
                case ARG_VERSION:
×
UNCOV
355
                        return version();
×
356

UNCOV
357
                case ARG_FORCE:
×
UNCOV
358
                        arg_import_flags |= IMPORT_FORCE;
×
UNCOV
359
                        break;
×
360

361
                case ARG_IMAGE_ROOT:
1✔
362
                        r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_image_root);
1✔
363
                        if (r < 0)
1✔
364
                                return r;
365

366
                        break;
367

368
                case ARG_VERIFY: {
26✔
369
                        ImportVerify v;
26✔
370

371
                        v = import_verify_from_string(optarg);
26✔
372
                        if (v < 0) {
26✔
373
                                _cleanup_free_ void *h = NULL;
8✔
374
                                char *hh;
8✔
375
                                size_t n;
8✔
376

377
                                /* If this is not a valid verification mode, maybe it's a literally specified
378
                                 * SHA256 hash? We can handle that too... */
379

380
                                r = unhexmem(optarg, &h, &n);
8✔
381
                                if (r < 0 || n == 0)
8✔
UNCOV
382
                                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
383
                                                               "Invalid verification setting: %s", optarg);
384
                                if (n != 32)
8✔
UNCOV
385
                                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
386
                                                               "64 hex character SHA256 hash required when specifying explicit checksum, %zu specified", n * 2);
387

388
                                hh = hexmem(h, n); /* bring into canonical (lowercase) form */
8✔
389
                                if (!hh)
8✔
UNCOV
390
                                        return log_oom();
×
391

392
                                free_and_replace(arg_checksum, hh);
8✔
393
                                arg_import_flags &= ~(IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY);
8✔
394
                                arg_verify = _IMPORT_VERIFY_INVALID;
8✔
395
                        } else
396
                                arg_verify = v;
18✔
397

398
                        break;
399
                }
400

401
                case ARG_SETTINGS:
×
402
                        r = parse_boolean_argument("--settings=", optarg, NULL);
×
UNCOV
403
                        if (r < 0)
×
404
                                return r;
405

UNCOV
406
                        SET_FLAG(arg_import_flags, IMPORT_PULL_SETTINGS, r);
×
UNCOV
407
                        auto_settings = false;
×
408
                        break;
×
409

UNCOV
410
                case ARG_ROOTHASH:
×
UNCOV
411
                        r = parse_boolean_argument("--roothash=", optarg, NULL);
×
412
                        if (r < 0)
×
413
                                return r;
414

UNCOV
415
                        SET_FLAG(arg_import_flags, IMPORT_PULL_ROOTHASH, r);
×
416

417
                        /* If we were asked to turn off the root hash, implicitly also turn off the root hash signature */
418
                        if (!r)
×
UNCOV
419
                                SET_FLAG(arg_import_flags, IMPORT_PULL_ROOTHASH_SIGNATURE, false);
×
420
                        break;
421

422
                case ARG_ROOTHASH_SIGNATURE:
×
UNCOV
423
                        r = parse_boolean_argument("--roothash-signature=", optarg, NULL);
×
UNCOV
424
                        if (r < 0)
×
425
                                return r;
426

UNCOV
427
                        SET_FLAG(arg_import_flags, IMPORT_PULL_ROOTHASH_SIGNATURE, r);
×
428
                        break;
×
429

430
                case ARG_VERITY:
×
UNCOV
431
                        r = parse_boolean_argument("--verity=", optarg, NULL);
×
UNCOV
432
                        if (r < 0)
×
433
                                return r;
434

UNCOV
435
                        SET_FLAG(arg_import_flags, IMPORT_PULL_VERITY, r);
×
UNCOV
436
                        break;
×
437

UNCOV
438
                case ARG_READ_ONLY:
×
UNCOV
439
                        arg_import_flags |= IMPORT_READ_ONLY;
×
UNCOV
440
                        break;
×
441

442
                case ARG_DIRECT:
20✔
443
                        arg_import_flags |= IMPORT_DIRECT;
20✔
444
                        arg_import_flags &= ~(IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY);
20✔
445
                        break;
20✔
446

447
                case ARG_BTRFS_SUBVOL:
4✔
448
                        r = parse_boolean_argument("--btrfs-subvol=", optarg, NULL);
4✔
449
                        if (r < 0)
4✔
450
                                return r;
451

452
                        SET_FLAG(arg_import_flags, IMPORT_BTRFS_SUBVOL, r);
4✔
453
                        break;
4✔
454

455
                case ARG_BTRFS_QUOTA:
×
UNCOV
456
                        r = parse_boolean_argument("--btrfs-quota=", optarg, NULL);
×
UNCOV
457
                        if (r < 0)
×
458
                                return r;
459

UNCOV
460
                        SET_FLAG(arg_import_flags, IMPORT_BTRFS_QUOTA, r);
×
UNCOV
461
                        break;
×
462

UNCOV
463
                case ARG_CONVERT_QCOW2:
×
UNCOV
464
                        r = parse_boolean_argument("--convert-qcow2=", optarg, NULL);
×
UNCOV
465
                        if (r < 0)
×
466
                                return r;
467

UNCOV
468
                        SET_FLAG(arg_import_flags, IMPORT_CONVERT_QCOW2, r);
×
UNCOV
469
                        break;
×
470

471
                case ARG_SYNC:
8✔
472
                        r = parse_boolean_argument("--sync=", optarg, NULL);
8✔
473
                        if (r < 0)
8✔
474
                                return r;
475

476
                        SET_FLAG(arg_import_flags, IMPORT_SYNC, r);
8✔
477
                        break;
8✔
478

479
                case ARG_OFFSET: {
4✔
480
                        uint64_t u;
4✔
481

482
                        r = safe_atou64(optarg, &u);
4✔
483
                        if (r < 0)
4✔
UNCOV
484
                                return log_error_errno(r, "Failed to parse --offset= argument: %s", optarg);
×
485
                        if (!FILE_SIZE_VALID(u))
4✔
UNCOV
486
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Argument to --offset= switch too large: %s", optarg);
×
487

488
                        arg_offset = u;
4✔
489
                        break;
4✔
490
                }
491

492
                case ARG_SIZE_MAX: {
4✔
493
                        uint64_t u;
4✔
494

495
                        r = parse_size(optarg, 1024, &u);
4✔
496
                        if (r < 0)
4✔
UNCOV
497
                                return log_error_errno(r, "Failed to parse --size-max= argument: %s", optarg);
×
498
                        if (!FILE_SIZE_VALID(u))
4✔
UNCOV
499
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Argument to --size-max= switch too large: %s", optarg);
×
500

501
                        arg_size_max = u;
4✔
502
                        break;
4✔
503
                }
504

505
                case ARG_CLASS:
6✔
506
                        arg_class = image_class_from_string(optarg);
6✔
507
                        if (arg_class < 0)
6✔
UNCOV
508
                                return log_error_errno(arg_class, "Failed to parse --class= argument: %s", optarg);
×
509

510
                        break;
511

512
                case ARG_KEEP_DOWNLOAD:
6✔
513
                        r = parse_boolean(optarg);
6✔
514
                        if (r < 0)
6✔
515
                                return log_error_errno(r, "Failed to parse --keep-download= argument: %s", optarg);
×
516

517
                        SET_FLAG(arg_import_flags, IMPORT_PULL_KEEP_DOWNLOAD, r);
6✔
518
                        auto_keep_download = false;
6✔
519
                        break;
6✔
520

521
                case ARG_SYSTEM:
6✔
522
                        arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
6✔
523
                        break;
6✔
524

525
                case ARG_USER:
×
UNCOV
526
                        arg_runtime_scope = RUNTIME_SCOPE_USER;
×
UNCOV
527
                        break;
×
528

529
                case '?':
530
                        return -EINVAL;
531

UNCOV
532
                default:
×
UNCOV
533
                        assert_not_reached();
×
534
                }
535

536
        /* Make sure offset+size is still in the valid range if both set */
537
        if (arg_offset != UINT64_MAX && arg_size_max != UINT64_MAX &&
26✔
538
            ((arg_size_max > (UINT64_MAX - arg_offset)) ||
4✔
539
             !FILE_SIZE_VALID(arg_offset + arg_size_max)))
4✔
UNCOV
540
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File offset und maximum size out of range.");
×
541

542
        if (arg_offset != UINT64_MAX && !FLAGS_SET(arg_import_flags, IMPORT_DIRECT))
26✔
UNCOV
543
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File offset only supported in --direct mode.");
×
544

545
        if (arg_checksum && (arg_import_flags & (IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY)) != 0)
26✔
UNCOV
546
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Literal checksum verification only supported if no associated files are downloaded.");
×
547

548
        if (!arg_image_root) {
26✔
549
                r = image_root_pick(arg_runtime_scope < 0 ? RUNTIME_SCOPE_SYSTEM : arg_runtime_scope, arg_class, /* runtime= */ false, &arg_image_root);
25✔
550
                if (r < 0)
25✔
UNCOV
551
                        return log_error_errno(r, "Failed to pick image root: %m");
×
552
        }
553

554
        /* .nspawn settings files only really make sense for machine images, not for sysext/confext/portable */
555
        if (auto_settings && arg_class != IMAGE_MACHINE)
26✔
556
                arg_import_flags &= ~IMPORT_PULL_SETTINGS;
6✔
557

558
        /* Keep the original pristine downloaded file as a copy only when dealing with machine images,
559
         * because unlike sysext/confext/portable they are typically modified during runtime. */
560
        if (auto_keep_download)
26✔
561
                SET_FLAG(arg_import_flags, IMPORT_PULL_KEEP_DOWNLOAD, arg_class == IMAGE_MACHINE);
20✔
562

563
        if (arg_runtime_scope == RUNTIME_SCOPE_USER)
26✔
UNCOV
564
                arg_import_flags |= IMPORT_FOREIGN_UID;
×
565

566
        return 1;
567
}
568

569
static void parse_env(void) {
26✔
570
        int r;
26✔
571

572
        /* Let's make these relatively low-level settings also controllable via env vars. User can then set
573
         * them for systemd-importd.service if they like to tweak behaviour */
574

575
        r = getenv_bool("SYSTEMD_IMPORT_BTRFS_SUBVOL");
26✔
576
        if (r >= 0)
26✔
UNCOV
577
                SET_FLAG(arg_import_flags, IMPORT_BTRFS_SUBVOL, r);
×
578
        else if (r != -ENXIO)
26✔
UNCOV
579
                log_warning_errno(r, "Failed to parse $SYSTEMD_IMPORT_BTRFS_SUBVOL: %m");
×
580

581
        r = getenv_bool("SYSTEMD_IMPORT_BTRFS_QUOTA");
26✔
582
        if (r >= 0)
26✔
UNCOV
583
                SET_FLAG(arg_import_flags, IMPORT_BTRFS_QUOTA, r);
×
584
        else if (r != -ENXIO)
26✔
UNCOV
585
                log_warning_errno(r, "Failed to parse $SYSTEMD_IMPORT_BTRFS_QUOTA: %m");
×
586

587
        r = getenv_bool("SYSTEMD_IMPORT_SYNC");
26✔
588
        if (r >= 0)
26✔
UNCOV
589
                SET_FLAG(arg_import_flags, IMPORT_SYNC, r);
×
590
        else if (r != -ENXIO)
26✔
UNCOV
591
                log_warning_errno(r, "Failed to parse $SYSTEMD_IMPORT_SYNC: %m");
×
592
}
26✔
593

594
static int pull_main(int argc, char *argv[]) {
26✔
595
        static const Verb verbs[] = {
26✔
596
                { "help", VERB_ANY, VERB_ANY, 0, help     },
597
                { "tar",  2,        3,        0, pull_tar },
598
                { "raw",  2,        3,        0, pull_raw },
599
                {}
600
        };
601

602
        return dispatch_verb(argc, argv, verbs, NULL);
26✔
603
}
604

605
static int run(int argc, char *argv[]) {
26✔
606
        int r;
26✔
607

608
        setlocale(LC_ALL, "");
26✔
609
        log_setup();
26✔
610

611
        parse_env();
26✔
612

613
        r = parse_argv(argc, argv);
26✔
614
        if (r <= 0)
26✔
615
                return r;
616

617
        (void) ignore_signals(SIGPIPE);
26✔
618

619
        return pull_main(argc, argv);
26✔
620
}
621

622
DEFINE_MAIN_FUNCTION(run);
26✔
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