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

systemd / systemd / 14630481637

23 Apr 2025 07:04PM UTC coverage: 72.178% (-0.002%) from 72.18%
14630481637

push

github

DaanDeMeyer
mkosi: Run clangd within the tools tree instead of the build container

Running within the build sandbox has a number of disadvantages:
- We have a separate clangd cache for each distribution/release combo
- It requires to build the full image before clangd can be used
- It breaks every time the image becomes out of date and requires a
  rebuild
- We can't look at system headers as we don't have the knowledge to map
  them from inside the build sandbox to the corresponding path on the host

Instead, let's have mkosi.clangd run clangd within the tools tree. We
already require building systemd for both the host and the target anyway,
and all the dependencies to build systemd are installed in the tools tree
already for that, as well as clangd since it's installed together with the
other clang tooling we install in the tools tree. Unlike the previous approach,
this approach only requires the mkosi tools tree to be built upfront, which has
a much higher chance of not invalidating its cache. We can also trivially map
system header lookups from within the sandbox to the path within mkosi.tools
on the host so that starts working as well.

297054 of 411557 relevant lines covered (72.18%)

686269.58 hits per line

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

75.45
/src/firstboot/firstboot.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <fcntl.h>
4
#include <getopt.h>
5
#include <linux/loop.h>
6
#include <unistd.h>
7

8
#include "sd-id128.h"
9

10
#include "alloc-util.h"
11
#include "ask-password-api.h"
12
#include "build.h"
13
#include "bus-error.h"
14
#include "bus-locator.h"
15
#include "bus-unit-util.h"
16
#include "bus-util.h"
17
#include "bus-wait-for-jobs.h"
18
#include "chase.h"
19
#include "copy.h"
20
#include "creds-util.h"
21
#include "dissect-image.h"
22
#include "env-file.h"
23
#include "errno-util.h"
24
#include "fd-util.h"
25
#include "fileio.h"
26
#include "fs-util.h"
27
#include "glyph-util.h"
28
#include "hostname-util.h"
29
#include "image-policy.h"
30
#include "kbd-util.h"
31
#include "libcrypt-util.h"
32
#include "locale-util.h"
33
#include "lock-util.h"
34
#include "main-func.h"
35
#include "memory-util.h"
36
#include "mkdir.h"
37
#include "mount-util.h"
38
#include "os-util.h"
39
#include "parse-argument.h"
40
#include "parse-util.h"
41
#include "password-quality-util.h"
42
#include "path-util.h"
43
#include "pretty-print.h"
44
#include "proc-cmdline.h"
45
#include "random-util.h"
46
#include "smack-util.h"
47
#include "string-util.h"
48
#include "strv.h"
49
#include "terminal-util.h"
50
#include "time-util.h"
51
#include "tmpfile-util-label.h"
52
#include "tmpfile-util.h"
53
#include "umask-util.h"
54
#include "user-util.h"
55
#include "vconsole-util.h"
56

57
static char *arg_root = NULL;
58
static char *arg_image = NULL;
59
static char *arg_locale = NULL;  /* $LANG */
60
static char *arg_locale_messages = NULL; /* $LC_MESSAGES */
61
static char *arg_keymap = NULL;
62
static char *arg_timezone = NULL;
63
static char *arg_hostname = NULL;
64
static sd_id128_t arg_machine_id = {};
65
static char *arg_root_password = NULL;
66
static char *arg_root_shell = NULL;
67
static char *arg_kernel_cmdline = NULL;
68
static bool arg_prompt_locale = false;
69
static bool arg_prompt_keymap = false;
70
static bool arg_prompt_timezone = false;
71
static bool arg_prompt_hostname = false;
72
static bool arg_prompt_root_password = false;
73
static bool arg_prompt_root_shell = false;
74
static bool arg_copy_locale = false;
75
static bool arg_copy_keymap = false;
76
static bool arg_copy_timezone = false;
77
static bool arg_copy_root_password = false;
78
static bool arg_copy_root_shell = false;
79
static bool arg_force = false;
80
static bool arg_delete_root_password = false;
81
static bool arg_root_password_is_hashed = false;
82
static bool arg_welcome = true;
83
static bool arg_reset = false;
84
static ImagePolicy *arg_image_policy = NULL;
85

86
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
135✔
87
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
135✔
88
STATIC_DESTRUCTOR_REGISTER(arg_locale, freep);
135✔
89
STATIC_DESTRUCTOR_REGISTER(arg_locale_messages, freep);
135✔
90
STATIC_DESTRUCTOR_REGISTER(arg_keymap, freep);
135✔
91
STATIC_DESTRUCTOR_REGISTER(arg_timezone, freep);
135✔
92
STATIC_DESTRUCTOR_REGISTER(arg_hostname, freep);
135✔
93
STATIC_DESTRUCTOR_REGISTER(arg_root_password, erase_and_freep);
135✔
94
STATIC_DESTRUCTOR_REGISTER(arg_root_shell, freep);
135✔
95
STATIC_DESTRUCTOR_REGISTER(arg_kernel_cmdline, freep);
135✔
96
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
135✔
97

98
static void print_welcome(int rfd) {
7✔
99
        _cleanup_free_ char *pretty_name = NULL, *os_name = NULL, *ansi_color = NULL;
7✔
100
        static bool done = false;
7✔
101
        const char *pn, *ac;
7✔
102
        int r;
7✔
103

104
        assert(rfd >= 0);
7✔
105

106
        if (!arg_welcome)
7✔
107
                return;
108

109
        if (done) {
6✔
110
                putchar('\n'); /* Add some breathing room between multiple prompts */
1✔
111
                return;
112
        }
113

114
        r = parse_os_release_at(rfd,
6✔
115
                                "PRETTY_NAME", &pretty_name,
116
                                "NAME", &os_name,
117
                                "ANSI_COLOR", &ansi_color);
118
        if (r < 0)
6✔
119
                log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
6✔
120
                               "Failed to read os-release file, ignoring: %m");
121

122
        pn = os_release_pretty_name(pretty_name, os_name);
6✔
123
        ac = isempty(ansi_color) ? "0" : ansi_color;
6✔
124

125
        (void) terminal_reset_defensive_locked(STDOUT_FILENO, /* flags= */ 0);
6✔
126

127
        if (colors_enabled())
6✔
128
                printf("\n"
×
129
                       ANSI_HIGHLIGHT "Welcome to your new installation of " ANSI_NORMAL "\x1B[%sm%s" ANSI_HIGHLIGHT "!" ANSI_NORMAL "\n", ac, pn);
130
        else
131
                printf("\nWelcome to your new installation of %s!\n", pn);
6✔
132

133
        putchar('\n');
6✔
134
        if (emoji_enabled()) {
6✔
135
                fputs(glyph(GLYPH_SPARKLES), stdout);
×
136
                putchar(' ');
×
137
        }
138
        printf("Please configure your new system!\n");
6✔
139

140
        any_key_to_proceed();
6✔
141

142
        done = true;
6✔
143
}
144

145
static int get_completions(
×
146
                const char *key,
147
                char ***ret_list,
148
                void *userdata) {
149

150
        int r;
×
151

152
        if (!userdata) {
×
153
                *ret_list = NULL;
×
154
                return 0;
×
155
        }
156

157
        _cleanup_strv_free_ char **copy = strv_copy(userdata);
×
158
        if (!copy)
×
159
                return -ENOMEM;
160

161
        r = strv_extend(&copy, "list");
×
162
        if (r < 0)
×
163
                return r;
164

165
        *ret_list = TAKE_PTR(copy);
×
166
        return 0;
×
167
}
168

169
static int prompt_loop(
7✔
170
                int rfd,
171
                const char *text,
172
                char **l,
173
                unsigned ellipsize_percentage,
174
                bool (*is_valid)(int rfd, const char *name),
175
                char **ret) {
176

177
        int r;
7✔
178

179
        assert(text);
7✔
180
        assert(is_valid);
7✔
181
        assert(ret);
7✔
182

183
        for (;;) {
7✔
184
                _cleanup_free_ char *p = NULL;
7✔
185

186
                r = ask_string_full(
7✔
187
                                &p,
188
                                get_completions,
189
                                l,
190
                                strv_isempty(l) ? "%s %s (empty to skip): "
7✔
191
                                                : "%s %s (empty to skip, \"list\" to list options): ",
192
                                glyph(GLYPH_TRIANGULAR_BULLET), text);
193
                if (r < 0)
7✔
194
                        return log_error_errno(r, "Failed to query user: %m");
×
195

196
                if (isempty(p)) {
7✔
197
                        log_info("No data entered, skipping.");
×
198
                        return 0;
×
199
                }
200

201
                if (!strv_isempty(l)) {
7✔
202
                        if (streq(p, "list")) {
4✔
203
                                r = show_menu(l,
×
204
                                              /* n_columns= */ 3,
205
                                              /* column_width= */ 20,
206
                                              ellipsize_percentage,
207
                                              /* grey_prefix= */ NULL,
208
                                              /* with_numbers= */ true);
209
                                if (r < 0)
×
210
                                        return log_error_errno(r, "Failed to show menu: %m");
×
211

212
                                putchar('\n');
×
213
                                continue;
×
214
                        }
215

216
                        unsigned u;
4✔
217
                        r = safe_atou(p, &u);
4✔
218
                        if (r >= 0) {
4✔
219
                                if (u <= 0 || u > strv_length(l)) {
×
220
                                        log_error("Specified entry number out of range.");
×
221
                                        continue;
×
222
                                }
223

224
                                log_info("Selected '%s'.", l[u-1]);
×
225
                                return free_and_strdup_warn(ret, l[u-1]);
×
226
                        }
227
                }
228

229
                if (is_valid(rfd, p))
7✔
230
                        return free_and_replace(*ret, p);
7✔
231

232
                /* Be more helpful to the user, and give a hint what the user might have wanted to type. */
233
                const char *best_match = strv_find_closest(l, p);
×
234
                if (best_match)
×
235
                        log_error("Invalid data '%s', did you mean '%s'?", p, best_match);
×
236
                else
237
                        log_error("Invalid data '%s'.", p);
×
238
        }
239
}
240

241
static int should_configure(int dir_fd, const char *filename) {
1,056✔
242
        _cleanup_fclose_ FILE *passwd = NULL, *shadow = NULL;
1,056✔
243
        int r;
1,056✔
244

245
        assert(dir_fd >= 0);
1,056✔
246
        assert(filename);
1,056✔
247

248
        if (streq(filename, "passwd") && !arg_force)
1,056✔
249
                /* We may need to do additional checks, so open the file. */
250
                r = xfopenat(dir_fd, filename, "re", O_NOFOLLOW, &passwd);
130✔
251
        else
252
                r = RET_NERRNO(faccessat(dir_fd, filename, F_OK, AT_SYMLINK_NOFOLLOW));
926✔
253

254
        if (r == -ENOENT)
513✔
255
                return true; /* missing */
256
        if (r < 0)
650✔
257
                return log_error_errno(r, "Failed to access %s: %m", filename);
×
258
        if (arg_force)
650✔
259
                return true; /* exists, but if --force was given we should still configure the file. */
260

261
        if (!passwd)
636✔
262
                return false;
263

264
        /* In case of /etc/passwd, do an additional check for the root password field.
265
         * We first check that passwd redirects to shadow, and then we check shadow.
266
         */
267
        struct passwd *i;
268
        while ((r = fgetpwent_sane(passwd, &i)) > 0) {
107✔
269
                if (!streq(i->pw_name, "root"))
106✔
270
                        continue;
×
271

272
                if (streq_ptr(i->pw_passwd, PASSWORD_SEE_SHADOW))
106✔
273
                        break;
274
                log_debug("passwd: root account with non-shadow password found, treating root as configured");
×
275
                return false;
276
        }
277
        if (r < 0)
107✔
278
                return log_error_errno(r, "Failed to read %s: %m", filename);
×
279
        if (r == 0) {
107✔
280
                log_debug("No root account found in %s, assuming root is not configured.", filename);
1✔
281
                return true;
1✔
282
        }
283

284
        r = xfopenat(dir_fd, "shadow", "re", O_NOFOLLOW, &shadow);
106✔
285
        if (r == -ENOENT) {
106✔
286
                log_debug("No shadow file found, assuming root is not configured.");
×
287
                return true; /* missing */
×
288
        }
289
        if (r < 0)
106✔
290
                return log_error_errno(r, "Failed to access shadow: %m");
×
291

292
        struct spwd *j;
293
        while ((r = fgetspent_sane(shadow, &j)) > 0) {
106✔
294
                if (!streq(j->sp_namp, "root"))
106✔
295
                        continue;
×
296

297
                bool unprovisioned = streq_ptr(j->sp_pwdp, PASSWORD_UNPROVISIONED);
106✔
298
                log_debug("Root account found, %s.",
206✔
299
                          unprovisioned ? "with unprovisioned password, treating root as not configured" :
300
                                          "treating root as configured");
301
                return unprovisioned;
106✔
302
        }
303
        if (r < 0)
×
304
                return log_error_errno(r, "Failed to read shadow: %m");
×
305
        assert(r == 0);
×
306
        log_debug("No root account found in shadow, assuming root is not configured.");
1,056✔
307
        return true;
308
}
309

310
static bool locale_is_installed_bool(const char *name) {
×
311
        return locale_is_installed(name) > 0;
×
312
}
313

314
static bool locale_is_ok(int rfd, const char *name) {
10✔
315
        int r;
10✔
316

317
        assert(rfd >= 0);
10✔
318

319
        r = dir_fd_is_root(rfd);
10✔
320
        if (r < 0)
10✔
321
                log_debug_errno(r, "Unable to determine if operating on host root directory, assuming we are: %m");
×
322

323
        return r != 0 ? locale_is_installed_bool(name) : locale_is_valid(name);
10✔
324
}
325

326
static int prompt_locale(int rfd) {
10✔
327
        _cleanup_strv_free_ char **locales = NULL;
×
328
        bool acquired_from_creds = false;
10✔
329
        int r;
10✔
330

331
        assert(rfd >= 0);
10✔
332

333
        if (arg_locale || arg_locale_messages)
10✔
334
                return 0;
335

336
        r = read_credential("firstboot.locale", (void**) &arg_locale, NULL);
6✔
337
        if (r < 0)
6✔
338
                log_debug_errno(r, "Failed to read credential firstboot.locale, ignoring: %m");
5✔
339
        else
340
                acquired_from_creds = true;
341

342
        r = read_credential("firstboot.locale-messages", (void**) &arg_locale_messages, NULL);
6✔
343
        if (r < 0)
6✔
344
                log_debug_errno(r, "Failed to read credential firstboot.locale-messages, ignoring: %m");
5✔
345
        else
346
                acquired_from_creds = true;
347

348
        if (acquired_from_creds) {
5✔
349
                log_debug("Acquired locale from credentials.");
1✔
350
                return 0;
1✔
351
        }
352

353
        if (!arg_prompt_locale) {
5✔
354
                log_debug("Prompting for locale was not requested.");
4✔
355
                return 0;
4✔
356
        }
357

358
        r = get_locales(&locales);
1✔
359
        if (r < 0)
1✔
360
                return log_error_errno(r, "Cannot query locales list: %m");
×
361

362
        if (strv_isempty(locales))
1✔
363
                log_debug("No locales found, skipping locale selection.");
×
364
        else if (strv_length(locales) == 1) {
1✔
365

366
                if (streq(locales[0], SYSTEMD_DEFAULT_LOCALE))
×
367
                        log_debug("Only installed locale is default locale anyway, not setting locale explicitly.");
×
368
                else {
369
                        log_debug("Only a single locale available (%s), selecting it as default.", locales[0]);
×
370

371
                        arg_locale = strdup(locales[0]);
×
372
                        if (!arg_locale)
×
373
                                return log_oom();
×
374

375
                        /* Not setting arg_locale_message here, since it defaults to LANG anyway */
376
                }
377
        } else {
378
                print_welcome(rfd);
1✔
379

380
                r = prompt_loop(rfd, "Please enter the new system locale name or number",
1✔
381
                                locales, 60, locale_is_ok, &arg_locale);
382
                if (r < 0)
1✔
383
                        return r;
384

385
                if (isempty(arg_locale))
11✔
386
                        return 0;
387

388
                r = prompt_loop(rfd, "Please enter the new system message locale name or number",
1✔
389
                                locales, 60, locale_is_ok, &arg_locale_messages);
390
                if (r < 0)
1✔
391
                        return r;
392

393
                /* Suppress the messages setting if it's the same as the main locale anyway */
394
                if (streq_ptr(arg_locale, arg_locale_messages))
1✔
395
                        arg_locale_messages = mfree(arg_locale_messages);
×
396
        }
397

398
        return 0;
399
}
400

401
static int process_locale(int rfd) {
132✔
402
        _cleanup_close_ int pfd = -EBADF;
132✔
403
        _cleanup_free_ char *f = NULL;
132✔
404
        char* locales[3];
132✔
405
        unsigned i = 0;
132✔
406
        int r;
132✔
407

408
        assert(rfd >= 0);
132✔
409

410
        pfd = chase_and_open_parent_at(rfd, "/etc/locale.conf",
132✔
411
                                       CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
412
                                       &f);
413
        if (pfd < 0)
132✔
414
                return log_error_errno(pfd, "Failed to chase /etc/locale.conf: %m");
×
415

416
        r = should_configure(pfd, f);
132✔
417
        if (r == 0)
132✔
418
                log_debug("Found /etc/locale.conf, assuming locale information has been configured.");
120✔
419
        if (r <= 0)
132✔
420
                return r;
421

422
        r = dir_fd_is_root(rfd);
12✔
423
        if (r < 0)
12✔
424
                return log_error_errno(r, "Failed to check if directory file descriptor is root: %m");
×
425

426
        if (arg_copy_locale && r == 0) {
12✔
427
                r = copy_file_atomic_at(AT_FDCWD, "/etc/locale.conf", pfd, f, 0644, COPY_REFLINK);
2✔
428
                if (r != -ENOENT) {
2✔
429
                        if (r < 0)
2✔
430
                                return log_error_errno(r, "Failed to copy host's /etc/locale.conf: %m");
×
431

432
                        log_info("Copied host's /etc/locale.conf.");
2✔
433
                        return 0;
2✔
434
                }
435
        }
436

437
        r = prompt_locale(rfd);
10✔
438
        if (r < 0)
10✔
439
                return r;
440

441
        if (!isempty(arg_locale))
10✔
442
                locales[i++] = strjoina("LANG=", arg_locale);
25✔
443
        if (!isempty(arg_locale_messages) && !streq_ptr(arg_locale_messages, arg_locale))
15✔
444
                locales[i++] = strjoina("LC_MESSAGES=", arg_locale_messages);
25✔
445

446
        if (i == 0)
10✔
447
                return 0;
448

449
        locales[i] = NULL;
6✔
450

451
        r = write_env_file(pfd, f, NULL, locales);
6✔
452
        if (r < 0)
6✔
453
                return log_error_errno(r, "Failed to write /etc/locale.conf: %m");
×
454

455
        log_info("/etc/locale.conf written.");
132✔
456
        return 1;
457
}
458

459
static bool keymap_exists_bool(const char *name) {
×
460
        return keymap_exists(name) > 0;
×
461
}
462

463
static bool keymap_is_ok(int rfd, const char* name) {
4✔
464
        int r;
4✔
465

466
        assert(rfd >= 0);
4✔
467

468
        r = dir_fd_is_root(rfd);
4✔
469
        if (r < 0)
4✔
470
                log_debug_errno(r, "Unable to determine if operating on host root directory, assuming we are: %m");
×
471

472
        return r != 0 ? keymap_exists_bool(name) : keymap_is_valid(name);
4✔
473
}
474

475
static int prompt_keymap(int rfd) {
12✔
476
        _cleanup_strv_free_ char **kmaps = NULL;
12✔
477
        int r;
12✔
478

479
        assert(rfd >= 0);
12✔
480

481
        if (arg_keymap)
12✔
482
                return 0;
483

484
        r = read_credential("firstboot.keymap", (void**) &arg_keymap, NULL);
10✔
485
        if (r < 0)
10✔
486
                log_debug_errno(r, "Failed to read credential firstboot.keymap, ignoring: %m");
9✔
487
        else {
488
                log_debug("Acquired keymap from credential.");
1✔
489
                return 0;
1✔
490
        }
491

492
        if (!arg_prompt_keymap) {
9✔
493
                log_debug("Prompting for keymap was not requested.");
8✔
494
                return 0;
8✔
495
        }
496

497
        r = get_keymaps(&kmaps);
1✔
498
        if (r == -ENOENT) /* no keymaps installed */
1✔
499
                return log_debug_errno(r, "No keymaps are installed.");
×
500
        if (r < 0)
1✔
501
                return log_error_errno(r, "Failed to read keymaps: %m");
×
502

503
        print_welcome(rfd);
1✔
504

505
        return prompt_loop(rfd, "Please enter the new keymap name or number",
1✔
506
                           kmaps, 60, keymap_is_ok, &arg_keymap);
507
}
508

509
static int process_keymap(int rfd) {
132✔
510
        _cleanup_close_ int pfd = -EBADF;
132✔
511
        _cleanup_free_ char *f = NULL;
132✔
512
        _cleanup_strv_free_ char **keymap = NULL;
×
513
        int r;
132✔
514

515
        assert(rfd >= 0);
132✔
516

517
        pfd = chase_and_open_parent_at(rfd, "/etc/vconsole.conf",
132✔
518
                                       CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
519
                                       &f);
520
        if (pfd < 0)
132✔
521
                return log_error_errno(pfd, "Failed to chase /etc/vconsole.conf: %m");
×
522

523
        r = should_configure(pfd, f);
132✔
524
        if (r == 0)
132✔
525
                log_debug("Found /etc/vconsole.conf, assuming console has been configured.");
118✔
526
        if (r <= 0)
132✔
527
                return r;
528

529
        r = dir_fd_is_root(rfd);
14✔
530
        if (r < 0)
14✔
531
                return log_error_errno(r, "Failed to check if directory file descriptor is root: %m");
×
532

533
        if (arg_copy_keymap && r == 0) {
14✔
534
                r = copy_file_atomic_at(AT_FDCWD, "/etc/vconsole.conf", pfd, f, 0644, COPY_REFLINK);
2✔
535
                if (r != -ENOENT) {
2✔
536
                        if (r < 0)
2✔
537
                                return log_error_errno(r, "Failed to copy host's /etc/vconsole.conf: %m");
×
538

539
                        log_info("Copied host's /etc/vconsole.conf.");
2✔
540
                        return 0;
2✔
541
                }
542
        }
543

544
        r = prompt_keymap(rfd);
12✔
545
        if (r == -ENOENT)
12✔
546
                return 0; /* don't fail if no keymaps are installed */
547
        if (r < 0)
12✔
548
                return r;
549

550
        if (isempty(arg_keymap))
136✔
551
                return 0;
552

553
        VCContext vc = {
4✔
554
                .keymap = arg_keymap,
555
        };
556
        _cleanup_(x11_context_clear) X11Context xc = {};
×
557

558
        r = vconsole_convert_to_x11(&vc, /* verify= */ NULL, &xc);
4✔
559
        if (r < 0)
4✔
560
                return log_error_errno(r, "Failed to convert keymap data: %m");
×
561

562
        r = vconsole_serialize(&vc, &xc, &keymap);
4✔
563
        if (r < 0)
4✔
564
                return log_error_errno(r, "Failed to serialize keymap data: %m");
×
565

566
        r = write_vconsole_conf(pfd, f, keymap);
4✔
567
        if (r < 0)
4✔
568
                return log_error_errno(r, "Failed to write /etc/vconsole.conf: %m");
×
569

570
        log_info("/etc/vconsole.conf written.");
4✔
571
        return 1;
572
}
573

574
static bool timezone_is_ok(int rfd, const char *name) {
1✔
575
        assert(rfd >= 0);
1✔
576

577
        return timezone_is_valid(name, LOG_DEBUG);
1✔
578
}
579

580
static int prompt_timezone(int rfd) {
71✔
581
        _cleanup_strv_free_ char **zones = NULL;
71✔
582
        int r;
71✔
583

584
        assert(rfd >= 0);
71✔
585

586
        if (arg_timezone)
71✔
587
                return 0;
588

589
        r = read_credential("firstboot.timezone", (void**) &arg_timezone, NULL);
69✔
590
        if (r < 0)
69✔
591
                log_debug_errno(r, "Failed to read credential firstboot.timezone, ignoring: %m");
11✔
592
        else {
593
                log_debug("Acquired timezone from credential.");
58✔
594
                return 0;
58✔
595
        }
596

597
        if (!arg_prompt_timezone) {
11✔
598
                log_debug("Prompting for timezone was not requested.");
10✔
599
                return 0;
10✔
600
        }
601

602
        r = get_timezones(&zones);
1✔
603
        if (r < 0)
1✔
604
                return log_error_errno(r, "Cannot query timezone list: %m");
×
605

606
        print_welcome(rfd);
1✔
607

608
        return prompt_loop(rfd, "Please enter the new timezone name or number",
1✔
609
                           zones, 30, timezone_is_ok, &arg_timezone);
610
}
611

612
static int process_timezone(int rfd) {
132✔
613
        _cleanup_close_ int pfd = -EBADF;
132✔
614
        _cleanup_free_ char *f = NULL;
132✔
615
        const char *e;
132✔
616
        int r;
132✔
617

618
        assert(rfd >= 0);
132✔
619

620
        pfd = chase_and_open_parent_at(rfd, "/etc/localtime",
132✔
621
                                       CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
622
                                       &f);
623
        if (pfd < 0)
132✔
624
                return log_error_errno(pfd, "Failed to chase /etc/localtime: %m");
×
625

626
        r = should_configure(pfd, f);
132✔
627
        if (r == 0)
132✔
628
                log_debug("Found /etc/localtime, assuming timezone has been configured.");
59✔
629
        if (r <= 0)
132✔
630
                return r;
631

632
        r = dir_fd_is_root(rfd);
73✔
633
        if (r < 0)
73✔
634
                return log_error_errno(r, "Failed to check if directory file descriptor is root: %m");
×
635

636
        if (arg_copy_timezone && r == 0) {
73✔
637
                _cleanup_free_ char *s = NULL;
2✔
638

639
                r = readlink_malloc("/etc/localtime", &s);
2✔
640
                if (r != -ENOENT) {
2✔
641
                        if (r < 0)
2✔
642
                                return log_error_errno(r, "Failed to read host's /etc/localtime: %m");
×
643

644
                        r = symlinkat_atomic_full(s, pfd, f, /* make_relative= */ false);
2✔
645
                        if (r < 0)
2✔
646
                                return log_error_errno(r, "Failed to create /etc/localtime symlink: %m");
×
647

648
                        log_info("Copied host's /etc/localtime.");
2✔
649
                        return 0;
2✔
650
                }
651
        }
652

653
        r = prompt_timezone(rfd);
71✔
654
        if (r < 0)
71✔
655
                return r;
656

657
        if (isempty(arg_timezone))
71✔
658
                return 0;
659

660
        e = strjoina("../usr/share/zoneinfo/", arg_timezone);
305✔
661

662
        r = symlinkat_atomic_full(e, pfd, f, /* make_relative= */ false);
61✔
663
        if (r < 0)
61✔
664
                return log_error_errno(r, "Failed to create /etc/localtime symlink: %m");
×
665

666
        log_info("/etc/localtime written");
132✔
667
        return 0;
668
}
669

670
static bool hostname_is_ok(int rfd, const char *name) {
1✔
671
        assert(rfd >= 0);
1✔
672

673
        return hostname_is_valid(name, VALID_HOSTNAME_TRAILING_DOT);
1✔
674
}
675

676
static int prompt_hostname(int rfd) {
118✔
677
        int r;
118✔
678

679
        assert(rfd >= 0);
118✔
680

681
        if (arg_hostname)
118✔
682
                return 0;
683

684
        if (!arg_prompt_hostname) {
116✔
685
                log_debug("Prompting for hostname was not requested.");
115✔
686
                return 0;
115✔
687
        }
688

689
        print_welcome(rfd);
1✔
690

691
        r = prompt_loop(rfd, "Please enter the new hostname",
1✔
692
                        NULL, 0, hostname_is_ok, &arg_hostname);
693
        if (r < 0)
1✔
694
                return r;
695

696
        if (arg_hostname)
1✔
697
                hostname_cleanup(arg_hostname);
1✔
698

699
        return 0;
700
}
701

702
static int process_hostname(int rfd) {
132✔
703
        _cleanup_close_ int pfd = -EBADF;
132✔
704
        _cleanup_free_ char *f = NULL;
132✔
705
        int r;
132✔
706

707
        assert(rfd >= 0);
132✔
708

709
        pfd = chase_and_open_parent_at(rfd, "/etc/hostname",
132✔
710
                                       CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN,
711
                                       &f);
712
        if (pfd < 0)
132✔
713
                return log_error_errno(pfd, "Failed to chase /etc/hostname: %m");
×
714

715
        r = should_configure(pfd, f);
132✔
716
        if (r == 0)
132✔
717
                log_debug("Found /etc/hostname, assuming hostname has been configured.");
14✔
718
        if (r <= 0)
132✔
719
                return r;
720

721
        r = prompt_hostname(rfd);
118✔
722
        if (r < 0)
118✔
723
                return r;
724

725
        if (isempty(arg_hostname))
118✔
726
                return 0;
727

728
        r = write_string_file_at(pfd, f, arg_hostname,
3✔
729
                                 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC);
730
        if (r < 0)
3✔
731
                return log_error_errno(r, "Failed to write /etc/hostname: %m");
×
732

733
        log_info("/etc/hostname written.");
132✔
734
        return 0;
735
}
736

737
static int process_machine_id(int rfd) {
132✔
738
        _cleanup_close_ int pfd = -EBADF;
132✔
739
        _cleanup_free_ char *f = NULL;
132✔
740
        int r;
132✔
741

742
        assert(rfd >= 0);
132✔
743

744
        pfd = chase_and_open_parent_at(rfd, "/etc/machine-id",
132✔
745
                                       CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
746
                                       &f);
747
        if (pfd < 0)
132✔
748
                return log_error_errno(pfd, "Failed to chase /etc/machine-id: %m");
×
749

750
        r = should_configure(pfd, f);
132✔
751
        if (r == 0)
132✔
752
                log_debug("Found /etc/machine-id, assuming machine-id has been configured.");
110✔
753
        if (r <= 0)
132✔
754
                return r;
755

756
        if (sd_id128_is_null(arg_machine_id)) {
22✔
757
                log_debug("Initialization of machine-id was not requested, skipping.");
19✔
758
                return 0;
19✔
759
        }
760

761
        r = write_string_file_at(pfd, "machine-id", SD_ID128_TO_STRING(arg_machine_id),
3✔
762
                                 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC);
763
        if (r < 0)
3✔
764
                return log_error_errno(r, "Failed to write /etc/machine-id: %m");
×
765

766
        log_info("/etc/machine-id written.");
132✔
767
        return 0;
768
}
769

770
static int prompt_root_password(int rfd) {
27✔
771
        const char *msg1, *msg2;
27✔
772
        int r;
27✔
773

774
        assert(rfd >= 0);
27✔
775

776
        if (arg_root_password)
27✔
777
                return 0;
778

779
        if (get_credential_user_password("root", &arg_root_password, &arg_root_password_is_hashed) >= 0)
18✔
780
                return 0;
781

782
        if (!arg_prompt_root_password) {
17✔
783
                log_debug("Prompting for root password was not requested.");
16✔
784
                return 0;
16✔
785
        }
786

787
        print_welcome(rfd);
1✔
788

789
        msg1 = strjoina(glyph(GLYPH_TRIANGULAR_BULLET), " Please enter the new root password (empty to skip):");
5✔
790
        msg2 = strjoina(glyph(GLYPH_TRIANGULAR_BULLET), " Please enter the new root password again:");
5✔
791

792
        suggest_passwords();
1✔
793

794
        for (;;) {
×
795
                _cleanup_strv_free_erase_ char **a = NULL, **b = NULL;
1✔
796
                _cleanup_free_ char *error = NULL;
1✔
797

798
                AskPasswordRequest req = {
1✔
799
                        .tty_fd = -EBADF,
800
                        .message = msg1,
801
                        .until = USEC_INFINITY,
802
                        .hup_fd = -EBADF,
803
                };
804

805
                r = ask_password_tty(&req, /* flags= */ 0, &a);
1✔
806
                if (r < 0)
1✔
807
                        return log_error_errno(r, "Failed to query root password: %m");
×
808
                if (strv_length(a) != 1)
1✔
809
                        return log_error_errno(SYNTHETIC_ERRNO(EIO),
×
810
                                               "Received multiple passwords, where we expected one.");
811

812
                if (isempty(*a)) {
1✔
813
                        log_info("No password entered, skipping.");
1✔
814
                        break;
815
                }
816

817
                r = check_password_quality(*a, /* old */ NULL, "root", &error);
×
818
                if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
×
819
                        log_warning("Password quality check is not supported, proceeding anyway.");
×
820
                else if (r < 0)
×
821
                        return log_error_errno(r, "Failed to check password quality: %m");
×
822
                else if (r == 0)
×
823
                        log_warning("Password is weak, accepting anyway: %s", error);
×
824

825
                req.message = msg2;
×
826

827
                r = ask_password_tty(&req, /* flags= */ 0, &b);
×
828
                if (r < 0)
×
829
                        return log_error_errno(r, "Failed to query root password: %m");
×
830
                if (strv_length(b) != 1)
×
831
                        return log_error_errno(SYNTHETIC_ERRNO(EIO),
×
832
                                               "Received multiple passwords, where we expected one.");
833

834
                if (!streq(*a, *b)) {
×
835
                        log_error("Entered passwords did not match, please try again.");
×
836
                        continue;
×
837
                }
838

839
                arg_root_password = TAKE_PTR(*a);
×
840
                break;
×
841
        }
842

843
        return 0;
1✔
844
}
845

846
static int find_shell(int rfd, const char *path) {
7✔
847
        int r;
7✔
848

849
        assert(path);
7✔
850

851
        if (!valid_shell(path))
7✔
852
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "%s is not a valid shell", path);
×
853

854
        r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT, NULL, NULL);
7✔
855
        if (r < 0)
7✔
856
                return log_error_errno(r, "Failed to resolve shell %s: %m", path);
1✔
857

858
        return 0;
859
}
860

861
static bool shell_is_ok(int rfd, const char *path) {
2✔
862
        assert(rfd >= 0);
2✔
863

864
        return find_shell(rfd, path) >= 0;
2✔
865
}
866

867
static int prompt_root_shell(int rfd) {
27✔
868
        int r;
27✔
869

870
        assert(rfd >= 0);
27✔
871

872
        if (arg_root_shell)
27✔
873
                return 0;
874

875
        r = read_credential("passwd.shell.root", (void**) &arg_root_shell, NULL);
22✔
876
        if (r < 0)
22✔
877
                log_debug_errno(r, "Failed to read credential passwd.shell.root, ignoring: %m");
21✔
878
        else {
879
                log_debug("Acquired root shell from credential.");
1✔
880
                return 0;
1✔
881
        }
882

883
        if (!arg_prompt_root_shell) {
21✔
884
                log_debug("Prompting for root shell was not requested.");
19✔
885
                return 0;
19✔
886
        }
887

888
        print_welcome(rfd);
2✔
889

890
        return prompt_loop(rfd, "Please enter the new root shell",
2✔
891
                           NULL, 0, shell_is_ok, &arg_root_shell);
892
}
893

894
static int write_root_passwd(int rfd, int etc_fd, const char *password, const char *shell) {
15✔
895
        _cleanup_fclose_ FILE *original = NULL, *passwd = NULL;
15✔
896
        _cleanup_(unlink_and_freep) char *passwd_tmp = NULL;
15✔
897
        int r;
15✔
898
        bool found = false;
15✔
899

900
        r = fopen_temporary_at_label(etc_fd, "passwd", "passwd", &passwd, &passwd_tmp);
15✔
901
        if (r < 0)
15✔
902
                return r;
903

904
        r = xfopenat(etc_fd, "passwd", "re", O_NOFOLLOW, &original);
15✔
905
        if (r < 0 && r != -ENOENT)
15✔
906
                return r;
907

908
        if (original) {
15✔
909
                struct passwd *i;
4✔
910

911
                r = copy_rights(fileno(original), fileno(passwd));
4✔
912
                if (r < 0)
4✔
913
                        return r;
×
914

915
                while ((r = fgetpwent_sane(original, &i)) > 0) {
7✔
916

917
                        if (streq(i->pw_name, "root")) {
3✔
918
                                if (password)
3✔
919
                                        i->pw_passwd = (char *) password;
2✔
920
                                if (shell)
3✔
921
                                        i->pw_shell = (char *) shell;
2✔
922
                                found = true;
923
                        }
924

925
                        r = putpwent_sane(i, passwd);
3✔
926
                        if (r < 0)
3✔
927
                                return r;
928
                }
929
                if (r < 0)
4✔
930
                        return r;
931

932
        } else {
933
                r = fchmod(fileno(passwd), 0644);
11✔
934
                if (r < 0)
11✔
935
                        return -errno;
×
936
        }
937

938
        if (!found) {
4✔
939
                struct passwd root = {
12✔
940
                        .pw_name = (char *) "root",
941
                        .pw_passwd = (char *) (password ?: PASSWORD_SEE_SHADOW),
12✔
942
                        .pw_uid = 0,
943
                        .pw_gid = 0,
944
                        .pw_gecos = (char *) "Super User",
945
                        .pw_dir = (char *) "/root",
946
                        .pw_shell = (char *) (shell ?: default_root_shell_at(rfd)),
6✔
947
                };
948

949
                if (errno != ENOENT)
12✔
950
                        return -errno;
×
951

952
                r = putpwent_sane(&root, passwd);
12✔
953
                if (r < 0)
12✔
954
                        return r;
955
        }
956

957
        r = fflush_sync_and_check(passwd);
15✔
958
        if (r < 0)
15✔
959
                return r;
960

961
        r = renameat_and_apply_smack_floor_label(etc_fd, passwd_tmp, etc_fd, "passwd");
15✔
962
        if (r < 0)
15✔
963
                return r;
×
964

965
        return 0;
966
}
967

968
static int write_root_shadow(int etc_fd, const char *hashed_password) {
15✔
969
        _cleanup_fclose_ FILE *original = NULL, *shadow = NULL;
15✔
970
        _cleanup_(unlink_and_freep) char *shadow_tmp = NULL;
15✔
971
        int r;
15✔
972
        bool found = false;
15✔
973

974
        r = fopen_temporary_at_label(etc_fd, "shadow", "shadow", &shadow, &shadow_tmp);
15✔
975
        if (r < 0)
15✔
976
                return r;
977

978
        r = xfopenat(etc_fd, "shadow", "re", O_NOFOLLOW, &original);
15✔
979
        if (r < 0 && r != -ENOENT)
15✔
980
                return r;
981

982
        if (original) {
15✔
983
                struct spwd *i;
4✔
984

985
                r = copy_rights(fileno(original), fileno(shadow));
4✔
986
                if (r < 0)
4✔
987
                        return r;
×
988

989
                while ((r = fgetspent_sane(original, &i)) > 0) {
7✔
990

991
                        if (streq(i->sp_namp, "root")) {
3✔
992
                                if (hashed_password) {
3✔
993
                                        i->sp_pwdp = (char *) hashed_password;
2✔
994
                                        i->sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
2✔
995
                                }
996
                                found = true;
997
                        }
998

999
                        r = putspent_sane(i, shadow);
3✔
1000
                        if (r < 0)
3✔
1001
                                return r;
1002
                }
1003
                if (r < 0)
4✔
1004
                        return r;
1005

1006
        } else {
1007
                r = fchmod(fileno(shadow), 0000);
11✔
1008
                if (r < 0)
11✔
1009
                        return -errno;
×
1010
        }
1011

1012
        if (!found) {
4✔
1013
                struct spwd root = {
36✔
1014
                        .sp_namp = (char*) "root",
1015
                        .sp_pwdp = (char *) (hashed_password ?: PASSWORD_LOCKED_AND_INVALID),
12✔
1016
                        .sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY),
12✔
1017
                        .sp_min = -1,
1018
                        .sp_max = -1,
1019
                        .sp_warn = -1,
1020
                        .sp_inact = -1,
1021
                        .sp_expire = -1,
1022
                        .sp_flag = ULONG_MAX, /* this appears to be what everybody does ... */
1023
                };
1024

1025
                if (errno != ENOENT)
12✔
1026
                        return -errno;
×
1027

1028
                r = putspent_sane(&root, shadow);
12✔
1029
                if (r < 0)
12✔
1030
                        return r;
1031
        }
1032

1033
        r = fflush_sync_and_check(shadow);
15✔
1034
        if (r < 0)
15✔
1035
                return r;
1036

1037
        r = renameat_and_apply_smack_floor_label(etc_fd, shadow_tmp, etc_fd, "shadow");
15✔
1038
        if (r < 0)
15✔
1039
                return r;
×
1040

1041
        return 0;
1042
}
1043

1044
static int process_root_account(int rfd) {
132✔
1045
        _cleanup_close_ int pfd = -EBADF;
132✔
1046
        _cleanup_(release_lock_file) LockFile lock = LOCK_FILE_INIT;
×
1047
        _cleanup_(erase_and_freep) char *_hashed_password = NULL;
132✔
1048
        const char *password, *hashed_password;
132✔
1049
        int k = 0, r;
132✔
1050

1051
        assert(rfd >= 0);
132✔
1052

1053
        pfd = chase_and_open_parent_at(rfd, "/etc/passwd",
132✔
1054
                                       CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
1055
                                       NULL);
1056
        if (pfd < 0)
132✔
1057
                return log_error_errno(pfd, "Failed to chase /etc/passwd: %m");
×
1058

1059
        /* Ensure that passwd and shadow are in the same directory and are not symlinks. */
1060

1061
        FOREACH_STRING(s, "passwd", "shadow") {
396✔
1062
                r = verify_regular_at(pfd, s, /* follow = */ false);
264✔
1063
                if (r < 0 && r != -ENOENT)
264✔
1064
                        return log_error_errno(r, "Verification of /etc/%s being regular file failed: %m", s);
×
1065

1066
                r = should_configure(pfd, s);
264✔
1067
                if (r < 0)
264✔
1068
                        return r;
1069

1070
                k += r;
264✔
1071
        }
1072

1073
        if (k == 0) {
132✔
1074
                log_debug("Found /etc/passwd and /etc/shadow, assuming root account has been initialized.");
105✔
1075
                return 0;
105✔
1076
        }
1077

1078
        r = make_lock_file_at(pfd, ETC_PASSWD_LOCK_FILENAME, LOCK_EX, &lock);
27✔
1079
        if (r < 0)
27✔
1080
                return log_error_errno(r, "Failed to take a lock on /etc/passwd: %m");
×
1081

1082
        k = dir_fd_is_root(rfd);
27✔
1083
        if (k < 0)
27✔
1084
                return log_error_errno(k, "Failed to check if directory file descriptor is root: %m");
×
1085

1086
        if (arg_copy_root_shell && k == 0) {
27✔
1087
                _cleanup_free_ struct passwd *p = NULL;
2✔
1088

1089
                r = getpwnam_malloc("root", &p);
2✔
1090
                if (r < 0)
2✔
1091
                        return log_error_errno(r, "Failed to find passwd entry for root: %m");
×
1092

1093
                r = free_and_strdup(&arg_root_shell, p->pw_shell);
2✔
1094
                if (r < 0)
2✔
1095
                        return log_oom();
×
1096
        }
1097

1098
        r = prompt_root_shell(rfd);
27✔
1099
        if (r < 0)
27✔
1100
                return r;
1101

1102
        if (arg_copy_root_password && k == 0) {
27✔
1103
                struct spwd *p;
2✔
1104

1105
                errno = 0;
2✔
1106
                p = getspnam("root");
2✔
1107
                if (!p)
2✔
1108
                        return log_error_errno(errno_or_else(EIO), "Failed to find shadow entry for root: %m");
×
1109

1110
                r = free_and_strdup(&arg_root_password, p->sp_pwdp);
2✔
1111
                if (r < 0)
2✔
1112
                        return log_oom();
×
1113

1114
                arg_root_password_is_hashed = true;
2✔
1115
        }
1116

1117
        r = prompt_root_password(rfd);
27✔
1118
        if (r < 0)
27✔
1119
                return r;
1120

1121
        if (arg_root_password && arg_root_password_is_hashed) {
27✔
1122
                password = PASSWORD_SEE_SHADOW;
1123
                hashed_password = arg_root_password;
1124
        } else if (arg_root_password) {
21✔
1125
                r = hash_password(arg_root_password, &_hashed_password);
4✔
1126
                if (r < 0)
4✔
1127
                        return log_error_errno(r, "Failed to hash password: %m");
×
1128

1129
                password = PASSWORD_SEE_SHADOW;
4✔
1130
                hashed_password = _hashed_password;
4✔
1131

1132
        } else if (arg_delete_root_password) {
17✔
1133
                password = PASSWORD_SEE_SHADOW;
1134
                hashed_password = PASSWORD_NONE;
1135
        } else if (!arg_root_password && arg_prompt_root_password) {
16✔
1136
                /* If the user was prompted, but no password was supplied, lock the account. */
1137
                password = PASSWORD_SEE_SHADOW;
1138
                hashed_password = PASSWORD_LOCKED_AND_INVALID;
1139
        } else
1140
                /* Leave the password as is. */
1141
                password = hashed_password = NULL;
15✔
1142

1143
        /* Don't create/modify passwd and shadow if there's nothing to do. */
1144
        if (!(password || hashed_password || arg_root_shell)) {
27✔
1145
                log_debug("Initialization of root account was not requested, skipping.");
12✔
1146
                return 0;
12✔
1147
        }
1148

1149
        r = write_root_passwd(rfd, pfd, password, arg_root_shell);
15✔
1150
        if (r < 0)
15✔
1151
                return log_error_errno(r, "Failed to write /etc/passwd: %m");
×
1152

1153
        log_info("/etc/passwd written.");
15✔
1154

1155
        r = write_root_shadow(pfd, hashed_password);
15✔
1156
        if (r < 0)
15✔
1157
                return log_error_errno(r, "Failed to write /etc/shadow: %m");
×
1158

1159
        log_info("/etc/shadow written.");
132✔
1160
        return 0;
1161
}
1162

1163
static int process_kernel_cmdline(int rfd) {
132✔
1164
        _cleanup_close_ int pfd = -EBADF;
132✔
1165
        _cleanup_free_ char *f = NULL;
132✔
1166
        int r;
132✔
1167

1168
        assert(rfd >= 0);
132✔
1169

1170
        pfd = chase_and_open_parent_at(rfd, "/etc/kernel/cmdline",
132✔
1171
                                       CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
1172
                                       &f);
1173
        if (pfd < 0)
132✔
1174
                return log_error_errno(pfd, "Failed to chase /etc/kernel/cmdline: %m");
×
1175

1176
        r = should_configure(pfd, f);
132✔
1177
        if (r == 0)
132✔
1178
                log_debug("Found /etc/kernel/cmdline, assuming kernel command line has been configured.");
1✔
1179
        if (r <= 0)
132✔
1180
                return r;
1181

1182
        if (!arg_kernel_cmdline) {
131✔
1183
                log_debug("Creation of /etc/kernel/cmdline was not requested, skipping.");
129✔
1184
                return 0;
129✔
1185
        }
1186

1187
        r = write_string_file_at(pfd, "cmdline", arg_kernel_cmdline,
2✔
1188
                                 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC);
1189
        if (r < 0)
2✔
1190
                return log_error_errno(r, "Failed to write /etc/kernel/cmdline: %m");
×
1191

1192
        log_info("/etc/kernel/cmdline written.");
132✔
1193
        return 0;
1194
}
1195

1196
static int reset_one(int rfd, const char *path) {
6✔
1197
        _cleanup_close_ int pfd = -EBADF;
6✔
1198
        _cleanup_free_ char *f = NULL;
6✔
1199

1200
        assert(rfd >= 0);
6✔
1201
        assert(path);
6✔
1202

1203
        pfd = chase_and_open_parent_at(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_WARN|CHASE_NOFOLLOW, &f);
6✔
1204
        if (pfd == -ENOENT)
6✔
1205
                return 0;
1206
        if (pfd < 0)
6✔
1207
                return log_error_errno(pfd, "Failed to resolve %s: %m", path);
×
1208

1209
        if (unlinkat(pfd, f, 0) < 0)
6✔
1210
                return errno == ENOENT ? 0 : log_error_errno(errno, "Failed to remove %s: %m", path);
×
1211

1212
        log_info("Removed %s", path);
6✔
1213
        return 0;
1214
}
1215

1216
static int process_reset(int rfd) {
132✔
1217
        int r;
132✔
1218

1219
        assert(rfd >= 0);
132✔
1220

1221
        if (!arg_reset)
132✔
1222
                return 0;
1223

1224
        FOREACH_STRING(p,
7✔
1225
                       "/etc/locale.conf",
1226
                       "/etc/vconsole.conf",
1227
                       "/etc/hostname",
1228
                       "/etc/machine-id",
1229
                       "/etc/kernel/cmdline",
1230
                       "/etc/localtime") {
1231
                r = reset_one(rfd, p);
6✔
1232
                if (r < 0)
6✔
1233
                        return r;
×
1234
        }
1235

1236
        return 0;
1✔
1237
}
1238

1239
static int help(void) {
×
1240
        _cleanup_free_ char *link = NULL;
×
1241
        int r;
×
1242

1243
        r = terminal_urlify_man("systemd-firstboot", "1", &link);
×
1244
        if (r < 0)
×
1245
                return log_oom();
×
1246

1247
        printf("%s [OPTIONS...]\n\n"
×
1248
               "Configures basic settings of the system.\n\n"
1249
               "  -h --help                       Show this help\n"
1250
               "     --version                    Show package version\n"
1251
               "     --root=PATH                  Operate on an alternate filesystem root\n"
1252
               "     --image=PATH                 Operate on disk image as filesystem root\n"
1253
               "     --image-policy=POLICY        Specify disk image dissection policy\n"
1254
               "     --locale=LOCALE              Set primary locale (LANG=)\n"
1255
               "     --locale-messages=LOCALE     Set message locale (LC_MESSAGES=)\n"
1256
               "     --keymap=KEYMAP              Set keymap\n"
1257
               "     --timezone=TIMEZONE          Set timezone\n"
1258
               "     --hostname=NAME              Set hostname\n"
1259
               "     --setup-machine-id           Set a random machine ID\n"
1260
               "     --machine-id=ID              Set specified machine ID\n"
1261
               "     --root-password=PASSWORD     Set root password from plaintext password\n"
1262
               "     --root-password-file=FILE    Set root password from file\n"
1263
               "     --root-password-hashed=HASH  Set root password from hashed password\n"
1264
               "     --root-shell=SHELL           Set root shell\n"
1265
               "     --kernel-command-line=CMDLINE\n"
1266
               "                                  Set kernel command line\n"
1267
               "     --prompt-locale              Prompt the user for locale settings\n"
1268
               "     --prompt-keymap              Prompt the user for keymap settings\n"
1269
               "     --prompt-timezone            Prompt the user for timezone\n"
1270
               "     --prompt-hostname            Prompt the user for hostname\n"
1271
               "     --prompt-root-password       Prompt the user for root password\n"
1272
               "     --prompt-root-shell          Prompt the user for root shell\n"
1273
               "     --prompt                     Prompt for all of the above\n"
1274
               "     --copy-locale                Copy locale from host\n"
1275
               "     --copy-keymap                Copy keymap from host\n"
1276
               "     --copy-timezone              Copy timezone from host\n"
1277
               "     --copy-root-password         Copy root password from host\n"
1278
               "     --copy-root-shell            Copy root shell from host\n"
1279
               "     --copy                       Copy locale, keymap, timezone, root password\n"
1280
               "     --force                      Overwrite existing files\n"
1281
               "     --delete-root-password       Delete root password\n"
1282
               "     --welcome=no                 Disable the welcome text\n"
1283
               "     --reset                      Remove existing files\n"
1284
               "\nSee the %s for details.\n",
1285
               program_invocation_short_name,
1286
               link);
1287

1288
        return 0;
1289
}
1290

1291
static int parse_argv(int argc, char *argv[]) {
135✔
1292

1293
        enum {
135✔
1294
                ARG_VERSION = 0x100,
1295
                ARG_ROOT,
1296
                ARG_IMAGE,
1297
                ARG_IMAGE_POLICY,
1298
                ARG_LOCALE,
1299
                ARG_LOCALE_MESSAGES,
1300
                ARG_KEYMAP,
1301
                ARG_TIMEZONE,
1302
                ARG_HOSTNAME,
1303
                ARG_SETUP_MACHINE_ID,
1304
                ARG_MACHINE_ID,
1305
                ARG_ROOT_PASSWORD,
1306
                ARG_ROOT_PASSWORD_FILE,
1307
                ARG_ROOT_PASSWORD_HASHED,
1308
                ARG_ROOT_SHELL,
1309
                ARG_KERNEL_COMMAND_LINE,
1310
                ARG_PROMPT,
1311
                ARG_PROMPT_LOCALE,
1312
                ARG_PROMPT_KEYMAP,
1313
                ARG_PROMPT_TIMEZONE,
1314
                ARG_PROMPT_HOSTNAME,
1315
                ARG_PROMPT_ROOT_PASSWORD,
1316
                ARG_PROMPT_ROOT_SHELL,
1317
                ARG_COPY,
1318
                ARG_COPY_LOCALE,
1319
                ARG_COPY_KEYMAP,
1320
                ARG_COPY_TIMEZONE,
1321
                ARG_COPY_ROOT_PASSWORD,
1322
                ARG_COPY_ROOT_SHELL,
1323
                ARG_FORCE,
1324
                ARG_DELETE_ROOT_PASSWORD,
1325
                ARG_WELCOME,
1326
                ARG_RESET,
1327
        };
1328

1329
        static const struct option options[] = {
135✔
1330
                { "help",                    no_argument,       NULL, 'h'                         },
1331
                { "version",                 no_argument,       NULL, ARG_VERSION                 },
1332
                { "root",                    required_argument, NULL, ARG_ROOT                    },
1333
                { "image",                   required_argument, NULL, ARG_IMAGE                   },
1334
                { "image-policy",            required_argument, NULL, ARG_IMAGE_POLICY            },
1335
                { "locale",                  required_argument, NULL, ARG_LOCALE                  },
1336
                { "locale-messages",         required_argument, NULL, ARG_LOCALE_MESSAGES         },
1337
                { "keymap",                  required_argument, NULL, ARG_KEYMAP                  },
1338
                { "timezone",                required_argument, NULL, ARG_TIMEZONE                },
1339
                { "hostname",                required_argument, NULL, ARG_HOSTNAME                },
1340
                { "setup-machine-id",        no_argument,       NULL, ARG_SETUP_MACHINE_ID        },
1341
                { "machine-id",              required_argument, NULL, ARG_MACHINE_ID              },
1342
                { "root-password",           required_argument, NULL, ARG_ROOT_PASSWORD           },
1343
                { "root-password-file",      required_argument, NULL, ARG_ROOT_PASSWORD_FILE      },
1344
                { "root-password-hashed",    required_argument, NULL, ARG_ROOT_PASSWORD_HASHED    },
1345
                { "root-shell",              required_argument, NULL, ARG_ROOT_SHELL              },
1346
                { "kernel-command-line",     required_argument, NULL, ARG_KERNEL_COMMAND_LINE     },
1347
                { "prompt",                  no_argument,       NULL, ARG_PROMPT                  },
1348
                { "prompt-locale",           no_argument,       NULL, ARG_PROMPT_LOCALE           },
1349
                { "prompt-keymap",           no_argument,       NULL, ARG_PROMPT_KEYMAP           },
1350
                { "prompt-timezone",         no_argument,       NULL, ARG_PROMPT_TIMEZONE         },
1351
                { "prompt-hostname",         no_argument,       NULL, ARG_PROMPT_HOSTNAME         },
1352
                { "prompt-root-password",    no_argument,       NULL, ARG_PROMPT_ROOT_PASSWORD    },
1353
                { "prompt-root-shell",       no_argument,       NULL, ARG_PROMPT_ROOT_SHELL       },
1354
                { "copy",                    no_argument,       NULL, ARG_COPY                    },
1355
                { "copy-locale",             no_argument,       NULL, ARG_COPY_LOCALE             },
1356
                { "copy-keymap",             no_argument,       NULL, ARG_COPY_KEYMAP             },
1357
                { "copy-timezone",           no_argument,       NULL, ARG_COPY_TIMEZONE           },
1358
                { "copy-root-password",      no_argument,       NULL, ARG_COPY_ROOT_PASSWORD      },
1359
                { "copy-root-shell",         no_argument,       NULL, ARG_COPY_ROOT_SHELL         },
1360
                { "force",                   no_argument,       NULL, ARG_FORCE                   },
1361
                { "delete-root-password",    no_argument,       NULL, ARG_DELETE_ROOT_PASSWORD    },
1362
                { "welcome",                 required_argument, NULL, ARG_WELCOME                 },
1363
                { "reset",                   no_argument,       NULL, ARG_RESET                   },
1364
                {}
1365
        };
1366

1367
        int r, c;
135✔
1368

1369
        assert(argc >= 0);
135✔
1370
        assert(argv);
135✔
1371

1372
        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
632✔
1373

1374
                switch (c) {
499✔
1375

1376
                case 'h':
×
1377
                        return help();
×
1378

1379
                case ARG_VERSION:
×
1380
                        return version();
×
1381

1382
                case ARG_ROOT:
35✔
1383
                        r = parse_path_argument(optarg, true, &arg_root);
35✔
1384
                        if (r < 0)
35✔
1385
                                return r;
1386
                        break;
1387

1388
                case ARG_IMAGE:
×
1389
                        r = parse_path_argument(optarg, false, &arg_image);
×
1390
                        if (r < 0)
×
1391
                                return r;
1392
                        break;
1393

1394
                case ARG_IMAGE_POLICY:
×
1395
                        r = parse_image_policy_argument(optarg, &arg_image_policy);
×
1396
                        if (r < 0)
×
1397
                                return r;
1398
                        break;
1399

1400
                case ARG_LOCALE:
4✔
1401
                        r = free_and_strdup(&arg_locale, optarg);
4✔
1402
                        if (r < 0)
4✔
1403
                                return log_oom();
×
1404

1405
                        break;
1406

1407
                case ARG_LOCALE_MESSAGES:
4✔
1408
                        r = free_and_strdup(&arg_locale_messages, optarg);
4✔
1409
                        if (r < 0)
4✔
1410
                                return log_oom();
×
1411

1412
                        break;
1413

1414
                case ARG_KEYMAP:
3✔
1415
                        if (!keymap_is_valid(optarg))
3✔
1416
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1417
                                                       "Keymap %s is not valid.", optarg);
1418

1419
                        r = free_and_strdup(&arg_keymap, optarg);
3✔
1420
                        if (r < 0)
3✔
1421
                                return log_oom();
×
1422

1423
                        break;
1424

1425
                case ARG_TIMEZONE:
4✔
1426
                        if (!timezone_is_valid(optarg, LOG_ERR))
4✔
1427
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1✔
1428
                                                       "Timezone %s is not valid.", optarg);
1429

1430
                        r = free_and_strdup(&arg_timezone, optarg);
3✔
1431
                        if (r < 0)
3✔
1432
                                return log_oom();
×
1433

1434
                        break;
1435

1436
                case ARG_ROOT_PASSWORD:
4✔
1437
                        r = free_and_strdup(&arg_root_password, optarg);
4✔
1438
                        if (r < 0)
4✔
1439
                                return log_oom();
×
1440

1441
                        arg_root_password_is_hashed = false;
4✔
1442
                        break;
4✔
1443

1444
                case ARG_ROOT_PASSWORD_FILE:
1✔
1445
                        arg_root_password = mfree(arg_root_password);
1✔
1446

1447
                        r = read_one_line_file(optarg, &arg_root_password);
1✔
1448
                        if (r < 0)
1✔
1449
                                return log_error_errno(r, "Failed to read %s: %m", optarg);
×
1450

1451
                        arg_root_password_is_hashed = false;
1✔
1452
                        break;
1✔
1453

1454
                case ARG_ROOT_PASSWORD_HASHED:
4✔
1455
                        r = free_and_strdup(&arg_root_password, optarg);
4✔
1456
                        if (r < 0)
4✔
1457
                                return log_oom();
×
1458

1459
                        arg_root_password_is_hashed = true;
4✔
1460
                        break;
4✔
1461

1462
                case ARG_ROOT_SHELL:
5✔
1463
                        r = free_and_strdup(&arg_root_shell, optarg);
5✔
1464
                        if (r < 0)
5✔
1465
                                return log_oom();
×
1466

1467
                        break;
1468

1469
                case ARG_HOSTNAME:
3✔
1470
                        if (!hostname_is_valid(optarg, VALID_HOSTNAME_TRAILING_DOT|VALID_HOSTNAME_QUESTION_MARK))
3✔
1471
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1472
                                                       "Host name %s is not valid.", optarg);
1473

1474
                        r = free_and_strdup(&arg_hostname, optarg);
3✔
1475
                        if (r < 0)
3✔
1476
                                return log_oom();
×
1477

1478
                        hostname_cleanup(arg_hostname);
3✔
1479
                        break;
3✔
1480

1481
                case ARG_SETUP_MACHINE_ID:
1✔
1482
                        r = sd_id128_randomize(&arg_machine_id);
1✔
1483
                        if (r < 0)
1✔
1484
                                return log_error_errno(r, "Failed to generate randomized machine ID: %m");
×
1485

1486
                        break;
1487

1488
                case ARG_MACHINE_ID:
4✔
1489
                        r = sd_id128_from_string(optarg, &arg_machine_id);
4✔
1490
                        if (r < 0)
4✔
1491
                                return log_error_errno(r, "Failed to parse machine id %s.", optarg);
1✔
1492

1493
                        break;
1494

1495
                case ARG_KERNEL_COMMAND_LINE:
3✔
1496
                        r = free_and_strdup(&arg_kernel_cmdline, optarg);
3✔
1497
                        if (r < 0)
3✔
1498
                                return log_oom();
×
1499

1500
                        break;
1501

1502
                case ARG_PROMPT:
×
1503
                        arg_prompt_locale = arg_prompt_keymap = arg_prompt_timezone = arg_prompt_hostname =
×
1504
                                arg_prompt_root_password = arg_prompt_root_shell = true;
×
1505
                        break;
×
1506

1507
                case ARG_PROMPT_LOCALE:
102✔
1508
                        arg_prompt_locale = true;
102✔
1509
                        break;
102✔
1510

1511
                case ARG_PROMPT_KEYMAP:
102✔
1512
                        arg_prompt_keymap = true;
102✔
1513
                        break;
102✔
1514

1515
                case ARG_PROMPT_TIMEZONE:
102✔
1516
                        arg_prompt_timezone = true;
102✔
1517
                        break;
102✔
1518

1519
                case ARG_PROMPT_HOSTNAME:
1✔
1520
                        arg_prompt_hostname = true;
1✔
1521
                        break;
1✔
1522

1523
                case ARG_PROMPT_ROOT_PASSWORD:
102✔
1524
                        arg_prompt_root_password = true;
102✔
1525
                        break;
102✔
1526

1527
                case ARG_PROMPT_ROOT_SHELL:
4✔
1528
                        arg_prompt_root_shell = true;
4✔
1529
                        break;
4✔
1530

1531
                case ARG_COPY:
1✔
1532
                        arg_copy_locale = arg_copy_keymap = arg_copy_timezone = arg_copy_root_password =
1✔
1533
                                arg_copy_root_shell = true;
1✔
1534
                        break;
1✔
1535

1536
                case ARG_COPY_LOCALE:
1✔
1537
                        arg_copy_locale = true;
1✔
1538
                        break;
1✔
1539

1540
                case ARG_COPY_KEYMAP:
1✔
1541
                        arg_copy_keymap = true;
1✔
1542
                        break;
1✔
1543

1544
                case ARG_COPY_TIMEZONE:
1✔
1545
                        arg_copy_timezone = true;
1✔
1546
                        break;
1✔
1547

1548
                case ARG_COPY_ROOT_PASSWORD:
1✔
1549
                        arg_copy_root_password = true;
1✔
1550
                        break;
1✔
1551

1552
                case ARG_COPY_ROOT_SHELL:
1✔
1553
                        arg_copy_root_shell = true;
1✔
1554
                        break;
1✔
1555

1556
                case ARG_FORCE:
2✔
1557
                        arg_force = true;
2✔
1558
                        break;
2✔
1559

1560
                case ARG_DELETE_ROOT_PASSWORD:
1✔
1561
                        arg_delete_root_password = true;
1✔
1562
                        break;
1✔
1563

1564
                case ARG_WELCOME:
1✔
1565
                        r = parse_boolean(optarg);
1✔
1566
                        if (r < 0)
1✔
1567
                                return log_error_errno(r, "Failed to parse --welcome= argument: %s", optarg);
×
1568

1569
                        arg_welcome = r;
1✔
1570
                        break;
1✔
1571

1572
                case ARG_RESET:
1✔
1573
                        arg_reset = true;
1✔
1574
                        break;
1✔
1575

1576
                case '?':
1577
                        return -EINVAL;
1578

1579
                default:
×
1580
                        assert_not_reached();
×
1581
                }
1582

1583
        if (arg_delete_root_password && (arg_copy_root_password || arg_root_password || arg_prompt_root_password))
133✔
1584
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1585
                                       "--delete-root-password cannot be combined with other root password options.");
1586

1587
        if (arg_image && arg_root)
133✔
1588
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1589
                                       "--root= and --image= cannot be used together.");
1590

1591
        if (!sd_id128_is_null(arg_machine_id) && !(arg_image || arg_root) && !arg_force)
262✔
1592
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1593
                                       "--machine-id=/--setup-machine-id only works with --root= or --image=.");
1594

1595
        return 1;
1596
}
1597

1598
static int reload_system_manager(sd_bus **bus) {
×
1599
        int r;
×
1600

1601
        assert(bus);
×
1602

1603
        if (!*bus) {
×
1604
                r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, RUNTIME_SCOPE_SYSTEM, bus);
×
1605
                if (r < 0)
×
1606
                        return bus_log_connect_error(r, BUS_TRANSPORT_LOCAL, RUNTIME_SCOPE_SYSTEM);
×
1607
        }
1608

1609
        r = bus_service_manager_reload(*bus);
×
1610
        if (r < 0)
×
1611
                return r;
1612

1613
        log_info("Requested manager reload to apply locale configuration.");
×
1614
        return 0;
1615
}
1616

1617
static int reload_vconsole(sd_bus **bus) {
×
1618
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
1619
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
×
1620
        _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
×
1621
        const char *object;
×
1622
        int r;
×
1623

1624
        assert(bus);
×
1625

1626
        if (!*bus) {
×
1627
                r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, RUNTIME_SCOPE_SYSTEM, bus);
×
1628
                if (r < 0)
×
1629
                        return bus_log_connect_error(r, BUS_TRANSPORT_LOCAL, RUNTIME_SCOPE_SYSTEM);
×
1630
        }
1631

1632
        r = bus_wait_for_jobs_new(*bus, &w);
×
1633
        if (r < 0)
×
1634
                return log_error_errno(r, "Could not watch jobs: %m");
×
1635

1636
        r = bus_call_method(*bus, bus_systemd_mgr, "RestartUnit", &error, &reply,
×
1637
                            "ss", "systemd-vconsole-setup.service", "replace");
1638
        if (r < 0)
×
1639
                return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
×
1640

1641
        r = sd_bus_message_read(reply, "o", &object);
×
1642
        if (r < 0)
×
1643
                return bus_log_parse_error(r);
×
1644

1645
        r = bus_wait_for_jobs_one(w, object, BUS_WAIT_JOBS_LOG_ERROR, NULL);
×
1646
        if (r < 0)
×
1647
                return log_error_errno(r, "Failed to wait for systemd-vconsole-setup.service/restart: %m");
×
1648
        return 0;
1649
}
1650

1651
static int run(int argc, char *argv[]) {
135✔
1652
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
135✔
1653
        _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
135✔
1654
        _cleanup_(umount_and_freep) char *mounted_dir = NULL;
×
1655
        _cleanup_close_ int rfd = -EBADF;
135✔
1656
        int r;
135✔
1657

1658
        r = parse_argv(argc, argv);
135✔
1659
        if (r <= 0)
135✔
1660
                return r;
1661

1662
        log_setup();
133✔
1663

1664
        umask(0022);
133✔
1665

1666
        bool offline = arg_root || arg_image;
133✔
1667

1668
        if (!offline) {
100✔
1669
                /* If we are called without --root=/--image= let's honour the systemd.firstboot kernel
1670
                 * command line option, because we are called to provision the host with basic settings (as
1671
                 * opposed to some other file system tree/image) */
1672

1673
                bool enabled;
100✔
1674
                r = proc_cmdline_get_bool("systemd.firstboot", /* flags = */ 0, &enabled);
100✔
1675
                if (r < 0)
100✔
1676
                        return log_error_errno(r, "Failed to parse systemd.firstboot= kernel command line argument, ignoring: %m");
×
1677
                if (r > 0 && !enabled) {
100✔
1678
                        log_debug("Found systemd.firstboot=no kernel command line argument, turning off all prompts.");
100✔
1679
                        arg_prompt_locale = arg_prompt_keymap = arg_prompt_timezone = arg_prompt_hostname = arg_prompt_root_password = arg_prompt_root_shell = false;
100✔
1680
                }
1681
        }
1682

1683
        if (arg_image) {
133✔
1684
                assert(!arg_root);
×
1685

1686
                r = mount_image_privately_interactively(
×
1687
                                arg_image,
1688
                                arg_image_policy,
1689
                                DISSECT_IMAGE_GENERIC_ROOT |
1690
                                DISSECT_IMAGE_REQUIRE_ROOT |
1691
                                DISSECT_IMAGE_VALIDATE_OS |
1692
                                DISSECT_IMAGE_RELAX_VAR_CHECK |
1693
                                DISSECT_IMAGE_FSCK |
1694
                                DISSECT_IMAGE_GROWFS |
1695
                                DISSECT_IMAGE_ALLOW_USERSPACE_VERITY,
1696
                                &mounted_dir,
1697
                                &rfd,
1698
                                &loop_device);
1699
                if (r < 0)
×
1700
                        return r;
1701

1702
                arg_root = strdup(mounted_dir);
×
1703
                if (!arg_root)
×
1704
                        return log_oom();
×
1705
        } else {
1706
                rfd = open(empty_to_root(arg_root), O_DIRECTORY|O_CLOEXEC);
166✔
1707
                if (rfd < 0)
133✔
1708
                        return log_error_errno(errno, "Failed to open %s: %m", empty_to_root(arg_root));
×
1709
        }
1710

1711
        LOG_SET_PREFIX(arg_image ?: arg_root);
268✔
1712

1713
        /* We check these conditions here instead of in parse_argv() so that we can take the root directory
1714
         * into account. */
1715

1716
        if (arg_keymap && !keymap_is_ok(rfd, arg_keymap))
133✔
1717
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Keymap %s is not installed.", arg_keymap);
×
1718
        if (arg_locale && !locale_is_ok(rfd, arg_locale))
133✔
1719
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale);
×
1720
        if (arg_locale_messages && !locale_is_ok(rfd, arg_locale_messages))
133✔
1721
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale_messages);
×
1722

1723
        if (arg_root_shell) {
133✔
1724
                r = find_shell(rfd, arg_root_shell);
5✔
1725
                if (r < 0)
5✔
1726
                        return r;
1727
        }
1728

1729
        r = process_reset(rfd);
132✔
1730
        if (r < 0)
132✔
1731
                return r;
1732

1733
        r = process_locale(rfd);
132✔
1734
        if (r < 0)
132✔
1735
                return r;
1736
        if (r > 0 && !offline)
132✔
1737
                (void) reload_system_manager(&bus);
×
1738

1739
        r = process_keymap(rfd);
132✔
1740
        if (r < 0)
132✔
1741
                return r;
1742
        if (r > 0 && !offline)
132✔
1743
                (void) reload_vconsole(&bus);
×
1744

1745
        r = process_timezone(rfd);
132✔
1746
        if (r < 0)
132✔
1747
                return r;
1748

1749
        r = process_hostname(rfd);
132✔
1750
        if (r < 0)
132✔
1751
                return r;
1752

1753
        r = process_root_account(rfd);
132✔
1754
        if (r < 0)
132✔
1755
                return r;
1756

1757
        r = process_kernel_cmdline(rfd);
132✔
1758
        if (r < 0)
132✔
1759
                return r;
1760

1761
        r = process_machine_id(rfd);
132✔
1762
        if (r < 0)
132✔
1763
                return r;
×
1764

1765
        return 0;
1766
}
1767

1768
DEFINE_MAIN_FUNCTION(run);
270✔
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