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

systemd / systemd / 18958539692

30 Oct 2025 09:15PM UTC coverage: 72.046% (-0.2%) from 72.245%
18958539692

push

github

web-flow
importd: port export-tar code to use the one systemd-dissect already uses (#39405)

Split out of #38728.

(Testcase is part of that PR)

92 of 135 new or added lines in 5 files covered. (68.15%)

4530 existing lines in 57 files now uncovered.

304067 of 422048 relevant lines covered (72.05%)

1172093.27 hits per line

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

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

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

6
#include "sd-event.h"
7

8
#include "alloc-util.h"
9
#include "ansi-color.h"
10
#include "build.h"
11
#include "discover-image.h"
12
#include "export-raw.h"
13
#include "export-tar.h"
14
#include "fd-util.h"
15
#include "import-common.h"
16
#include "log.h"
17
#include "main-func.h"
18
#include "runtime-scope.h"
19
#include "signal-util.h"
20
#include "string-util.h"
21
#include "terminal-util.h"
22
#include "verbs.h"
23

24
static ImportFlags arg_import_flags = 0;
25
static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN;
26
static ImageClass arg_class = IMAGE_MACHINE;
27
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
28

29
static void determine_compression_from_filename(const char *p) {
11✔
30

31
        if (arg_compress != IMPORT_COMPRESS_UNKNOWN)
11✔
32
                return;
33

34
        if (!p) {
6✔
35
                arg_compress = IMPORT_COMPRESS_UNCOMPRESSED;
6✔
36
                return;
6✔
37
        }
38

39
        if (endswith(p, ".xz"))
×
40
                arg_compress = IMPORT_COMPRESS_XZ;
×
41
        else if (endswith(p, ".gz"))
×
42
                arg_compress = IMPORT_COMPRESS_GZIP;
×
43
        else if (endswith(p, ".bz2"))
×
44
                arg_compress = IMPORT_COMPRESS_BZIP2;
×
45
        else if (endswith(p, ".zst"))
×
46
                arg_compress = IMPORT_COMPRESS_ZSTD;
×
47
        else
48
                arg_compress = IMPORT_COMPRESS_UNCOMPRESSED;
×
49
}
50

51
static void on_tar_finished(TarExport *export, int error, void *userdata) {
4✔
52
        sd_event *event = userdata;
4✔
53
        assert(export);
4✔
54

55
        if (error == 0)
4✔
56
                log_info("Operation completed successfully.");
4✔
57

58
        sd_event_exit(event, ABS(error));
4✔
59
}
4✔
60

61
static int export_tar(int argc, char *argv[], void *userdata) {
4✔
62
        _cleanup_(tar_export_unrefp) TarExport *export = NULL;
×
63
        _cleanup_(sd_event_unrefp) sd_event *event = NULL;
4✔
64
        _cleanup_(image_unrefp) Image *image = NULL;
×
65
        const char *path = NULL, *local = NULL;
4✔
66
        _cleanup_close_ int open_fd = -EBADF;
4✔
67
        int r, fd;
4✔
68

69
        local = argv[1];
4✔
70
        if (image_name_is_valid(local)) {
4✔
71
                r = image_find(arg_runtime_scope, arg_class, local, NULL, &image);
4✔
72
                if (r == -ENOENT)
4✔
73
                        return log_error_errno(r, "Image %s not found.", local);
×
74
                if (r < 0)
4✔
75
                        return log_error_errno(r, "Failed to look for image %s: %m", local);
×
76

77
                local = image->path;
4✔
78
        } else
79
                local = argv[1];
80

81
        if (argc >= 3)
4✔
82
                path = argv[2];
×
83
        path = empty_or_dash_to_null(path);
×
84

85
        determine_compression_from_filename(path);
4✔
86

87
        if (path) {
4✔
88
                open_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
×
89
                if (open_fd < 0)
×
90
                        return log_error_errno(errno, "Failed to open tar image for export: %m");
×
91

92
                fd = open_fd;
×
93

94
                log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, path, import_compress_type_to_string(arg_compress));
×
95
        } else {
96
                _cleanup_free_ char *pretty = NULL;
4✔
97

98
                if (isatty_safe(STDOUT_FILENO))
4✔
99
                        return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Refusing to write archive to TTY.");
×
100

101
                fd = STDOUT_FILENO;
4✔
102

103
                (void) fd_get_path(fd, &pretty);
4✔
104
                log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, strna(pretty), import_compress_type_to_string(arg_compress));
4✔
105
        }
106

107
        r = import_allocate_event_with_signals(&event);
4✔
108
        if (r < 0)
4✔
109
                return r;
110

111
        r = tar_export_new(&export, event, on_tar_finished, event);
4✔
112
        if (r < 0)
4✔
113
                return log_error_errno(r, "Failed to allocate exporter: %m");
×
114

115
        r = tar_export_start(
8✔
116
                        export,
117
                        local,
118
                        fd,
119
                        arg_compress,
120
                        arg_import_flags & IMPORT_FLAGS_MASK_TAR);
4✔
121
        if (r < 0)
4✔
122
                return log_error_errno(r, "Failed to export image: %m");
×
123

124
        r = sd_event_loop(event);
4✔
125
        if (r < 0)
4✔
126
                return log_error_errno(r, "Failed to run event loop: %m");
×
127

128
        log_info("Exiting.");
4✔
129
        return -r;
4✔
130
}
131

132
static void on_raw_finished(RawExport *export, int error, void *userdata) {
7✔
133
        sd_event *event = userdata;
7✔
134
        assert(export);
7✔
135

136
        if (error == 0)
7✔
137
                log_info("Operation completed successfully.");
7✔
138

139
        sd_event_exit(event, ABS(error));
7✔
140
}
7✔
141

142
static int export_raw(int argc, char *argv[], void *userdata) {
7✔
143
        _cleanup_(raw_export_unrefp) RawExport *export = NULL;
×
144
        _cleanup_(sd_event_unrefp) sd_event *event = NULL;
7✔
145
        _cleanup_(image_unrefp) Image *image = NULL;
×
146
        const char *path = NULL, *local = NULL;
7✔
147
        _cleanup_close_ int open_fd = -EBADF;
7✔
148
        int r, fd;
7✔
149

150
        local = argv[1];
7✔
151
        if (image_name_is_valid(local)) {
7✔
152
                r = image_find(arg_runtime_scope, arg_class, local, NULL, &image);
7✔
153
                if (r == -ENOENT)
7✔
154
                        return log_error_errno(r, "Image %s not found.", local);
×
155
                if (r < 0)
7✔
156
                        return log_error_errno(r, "Failed to look for image %s: %m", local);
×
157

158
                local = image->path;
7✔
159
        } else
160
                local = argv[1];
161

162
        if (argc >= 3)
7✔
163
                path = argv[2];
×
164
        path = empty_or_dash_to_null(path);
×
165

166
        determine_compression_from_filename(path);
7✔
167

168
        if (path) {
7✔
169
                open_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
×
170
                if (open_fd < 0)
×
171
                        return log_error_errno(errno, "Failed to open raw image for export: %m");
×
172

173
                fd = open_fd;
×
174

175
                log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, path, import_compress_type_to_string(arg_compress));
×
176
        } else {
177
                _cleanup_free_ char *pretty = NULL;
7✔
178

179
                fd = STDOUT_FILENO;
7✔
180

181
                (void) fd_get_path(fd, &pretty);
7✔
182
                log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, strna(pretty), import_compress_type_to_string(arg_compress));
7✔
183
        }
184

185
        r = import_allocate_event_with_signals(&event);
7✔
186
        if (r < 0)
7✔
187
                return r;
188

189
        r = raw_export_new(&export, event, on_raw_finished, event);
7✔
190
        if (r < 0)
7✔
191
                return log_error_errno(r, "Failed to allocate exporter: %m");
×
192

193
        r = raw_export_start(export, local, fd, arg_compress);
7✔
194
        if (r < 0)
7✔
195
                return log_error_errno(r, "Failed to export image: %m");
×
196

197
        r = sd_event_loop(event);
7✔
198
        if (r < 0)
7✔
199
                return log_error_errno(r, "Failed to run event loop: %m");
×
200

201
        log_info("Exiting.");
7✔
202
        return -r;
7✔
203
}
204

205
static int help(int argc, char *argv[], void *userdata) {
×
206
        printf("%1$s [OPTIONS...] {COMMAND} ...\n"
×
207
               "\n%4$sExport disk images.%5$s\n"
208
               "\n%2$sCommands:%3$s\n"
209
               "  tar NAME [FILE]              Export a TAR image\n"
210
               "  raw NAME [FILE]              Export a RAW image\n"
211
               "\n%2$sOptions:%3$s\n"
212
               "  -h --help                    Show this help\n"
213
               "     --version                 Show package version\n"
214
               "     --format=FORMAT           Select format\n"
215
               "     --class=CLASS             Select image class (machine, sysext, confext,\n"
216
               "                               portable)\n"
217
               "     --system                  Operate in per-system mode\n"
218
               "     --user                    Operate in per-user mode\n",
219
               program_invocation_short_name,
220
               ansi_underline(),
221
               ansi_normal(),
222
               ansi_highlight(),
223
               ansi_normal());
224

225
        return 0;
×
226
}
227

228
static int parse_argv(int argc, char *argv[]) {
11✔
229

230
        enum {
11✔
231
                ARG_VERSION = 0x100,
232
                ARG_FORMAT,
233
                ARG_CLASS,
234
                ARG_SYSTEM,
235
                ARG_USER,
236
        };
237

238
        static const struct option options[] = {
11✔
239
                { "help",    no_argument,       NULL, 'h'         },
240
                { "version", no_argument,       NULL, ARG_VERSION },
241
                { "format",  required_argument, NULL, ARG_FORMAT  },
242
                { "class",   required_argument, NULL, ARG_CLASS   },
243
                { "system",  no_argument,       NULL, ARG_SYSTEM  },
244
                { "user",    no_argument,       NULL, ARG_USER    },
245
                {}
246
        };
247

248
        int c;
11✔
249

250
        assert(argc >= 0);
11✔
251
        assert(argv);
11✔
252

253
        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
30✔
254

255
                switch (c) {
19✔
256

257
                case 'h':
×
258
                        return help(0, NULL, NULL);
×
259

260
                case ARG_VERSION:
×
261
                        return version();
×
262

263
                case ARG_FORMAT:
5✔
264
                        arg_compress = import_compress_type_from_string(optarg);
5✔
265
                        if (arg_compress < 0 || arg_compress == IMPORT_COMPRESS_UNKNOWN)
5✔
266
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
267
                                                       "Unknown format: %s", optarg);
268
                        break;
269

270
                case ARG_CLASS:
3✔
271
                        arg_class = image_class_from_string(optarg);
3✔
272
                        if (arg_class < 0)
3✔
273
                                return log_error_errno(arg_class, "Failed to parse --class= argument: %s", optarg);
×
274

275
                        break;
276

277
                case ARG_SYSTEM:
11✔
278
                        arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
11✔
279
                        break;
11✔
280

281
                case ARG_USER:
×
282
                        arg_runtime_scope = RUNTIME_SCOPE_USER;
×
283
                        break;
×
284

285
                case '?':
286
                        return -EINVAL;
287

288
                default:
×
289
                        assert_not_reached();
×
290
                }
291

292
        if (arg_runtime_scope == RUNTIME_SCOPE_USER)
11✔
NEW
293
                arg_import_flags |= IMPORT_FOREIGN_UID;
×
294

295
        return 1;
296
}
297

298
static int export_main(int argc, char *argv[]) {
11✔
299
        static const Verb verbs[] = {
11✔
300
                { "help", VERB_ANY, VERB_ANY, 0, help       },
301
                { "tar",  2,        3,        0, export_tar },
302
                { "raw",  2,        3,        0, export_raw },
303
                {}
304
        };
305

306
        return dispatch_verb(argc, argv, verbs, NULL);
11✔
307
}
308

309
static int run(int argc, char *argv[]) {
11✔
310
        int r;
11✔
311

312
        setlocale(LC_ALL, "");
11✔
313
        log_setup();
11✔
314

315
        r = parse_argv(argc, argv);
11✔
316
        if (r <= 0)
11✔
317
                return r;
318

319
        (void) ignore_signals(SIGPIPE);
11✔
320

321
        return export_main(argc, argv);
11✔
322
}
323

324
DEFINE_MAIN_FUNCTION(run);
11✔
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