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

systemd / systemd / 17992912793

24 Sep 2025 07:15PM UTC coverage: 72.205% (-0.08%) from 72.283%
17992912793

push

github

web-flow
libblkid → turn into dlopen() dependency (#39084)

Split out of #38861

153 of 207 new or added lines in 10 files covered. (73.91%)

1717 existing lines in 53 files now uncovered.

302842 of 419419 relevant lines covered (72.21%)

1052332.54 hits per line

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

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

3
#include <fcntl.h>
4
#include <getopt.h>
5
#include <unistd.h>
6

7
#include "sd-bus.h"
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 "label.h"
32
#include "label-util.h"
33
#include "libcrypt-util.h"
34
#include "locale-setup.h"
35
#include "locale-util.h"
36
#include "lock-util.h"
37
#include "loop-util.h"
38
#include "main-func.h"
39
#include "memory-util.h"
40
#include "mount-util.h"
41
#include "os-util.h"
42
#include "parse-argument.h"
43
#include "parse-util.h"
44
#include "password-quality-util.h"
45
#include "path-util.h"
46
#include "pretty-print.h"
47
#include "proc-cmdline.h"
48
#include "prompt-util.h"
49
#include "runtime-scope.h"
50
#include "smack-util.h"
51
#include "stat-util.h"
52
#include "string-util.h"
53
#include "strv.h"
54
#include "terminal-util.h"
55
#include "time-util.h"
56
#include "tmpfile-util-label.h"
57
#include "user-util.h"
58
#include "vconsole-util.h"
59

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

90
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
141✔
91
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
141✔
92
STATIC_DESTRUCTOR_REGISTER(arg_locale, freep);
141✔
93
STATIC_DESTRUCTOR_REGISTER(arg_locale_messages, freep);
141✔
94
STATIC_DESTRUCTOR_REGISTER(arg_keymap, freep);
141✔
95
STATIC_DESTRUCTOR_REGISTER(arg_timezone, freep);
141✔
96
STATIC_DESTRUCTOR_REGISTER(arg_hostname, freep);
141✔
97
STATIC_DESTRUCTOR_REGISTER(arg_root_password, erase_and_freep);
141✔
98
STATIC_DESTRUCTOR_REGISTER(arg_root_shell, freep);
141✔
99
STATIC_DESTRUCTOR_REGISTER(arg_kernel_cmdline, freep);
141✔
100
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
141✔
101

102
static void print_welcome(int rfd) {
7✔
103
        _cleanup_free_ char *pretty_name = NULL, *os_name = NULL, *ansi_color = NULL;
7✔
104
        static bool done = false;
7✔
105
        const char *pn, *ac;
7✔
106
        int r;
7✔
107

108
        assert(rfd >= 0);
7✔
109

110
        if (!arg_welcome)
7✔
111
                return;
112

113
        if (done) {
6✔
114
                putchar('\n'); /* Add some breathing room between multiple prompts */
1✔
115
                return;
116
        }
117

118
        (void) terminal_reset_defensive_locked(STDOUT_FILENO, /* flags= */ 0);
6✔
119

120
        if (arg_chrome)
6✔
121
                chrome_show("Initial Setup", /* bottom= */ NULL);
6✔
122

123
        r = parse_os_release_at(rfd,
6✔
124
                                "PRETTY_NAME", &pretty_name,
125
                                "NAME", &os_name,
126
                                "ANSI_COLOR", &ansi_color);
127
        if (r < 0)
6✔
128
                log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
6✔
129
                               "Failed to read os-release file, ignoring: %m");
130

131
        pn = os_release_pretty_name(pretty_name, os_name);
6✔
132
        ac = isempty(ansi_color) ? "0" : ansi_color;
6✔
133

134
        if (colors_enabled())
6✔
UNCOV
135
                printf(ANSI_HIGHLIGHT "Welcome to your new installation of " ANSI_NORMAL "\x1B[%sm%s" ANSI_HIGHLIGHT "!" ANSI_NORMAL "\n", ac, pn);
×
136
        else
137
                printf("Welcome to your new installation of %s!\n", pn);
6✔
138

139
        putchar('\n');
6✔
140
        if (emoji_enabled()) {
6✔
UNCOV
141
                fputs(glyph(GLYPH_SPARKLES), stdout);
×
UNCOV
142
                putchar(' ');
×
143
        }
144
        printf("Please configure your new system!\n");
6✔
145

146
        any_key_to_proceed();
6✔
147

148
        done = true;
6✔
149
}
150

151
static int should_configure(int dir_fd, const char *filename) {
1,104✔
152
        _cleanup_fclose_ FILE *passwd = NULL, *shadow = NULL;
1,104✔
153
        int r;
1,104✔
154

155
        assert(dir_fd >= 0);
1,104✔
156
        assert(filename);
1,104✔
157

158
        if (streq(filename, "passwd") && !arg_force)
1,104✔
159
                /* We may need to do additional checks, so open the file. */
160
                r = xfopenat(dir_fd, filename, "re", O_NOFOLLOW, &passwd);
135✔
161
        else
162
                r = RET_NERRNO(faccessat(dir_fd, filename, F_OK, AT_SYMLINK_NOFOLLOW));
969✔
163

164
        if (r == -ENOENT)
584✔
165
                return true; /* missing */
166
        if (r < 0)
631✔
167
                return log_error_errno(r, "Failed to access %s: %m", filename);
×
168
        if (arg_force)
631✔
169
                return true; /* exists, but if --force was given we should still configure the file. */
170

171
        if (!passwd)
613✔
172
                return false;
173

174
        /* In case of /etc/passwd, do an additional check for the root password field.
175
         * We first check that passwd redirects to shadow, and then we check shadow.
176
         */
177
        struct passwd *i;
178
        while ((r = fgetpwent_sane(passwd, &i)) > 0) {
111✔
179
                if (!streq(i->pw_name, "root"))
110✔
UNCOV
180
                        continue;
×
181

182
                if (streq_ptr(i->pw_passwd, PASSWORD_SEE_SHADOW))
110✔
183
                        break;
UNCOV
184
                log_debug("passwd: root account with non-shadow password found, treating root as configured");
×
185
                return false;
186
        }
187
        if (r < 0)
111✔
UNCOV
188
                return log_error_errno(r, "Failed to read %s: %m", filename);
×
189
        if (r == 0) {
111✔
190
                log_debug("No root account found in %s, assuming root is not configured.", filename);
1✔
191
                return true;
1✔
192
        }
193

194
        r = xfopenat(dir_fd, "shadow", "re", O_NOFOLLOW, &shadow);
110✔
195
        if (r == -ENOENT) {
110✔
196
                log_debug("No shadow file found, assuming root is not configured.");
×
UNCOV
197
                return true; /* missing */
×
198
        }
199
        if (r < 0)
110✔
200
                return log_error_errno(r, "Failed to access shadow: %m");
×
201

202
        struct spwd *j;
203
        while ((r = fgetspent_sane(shadow, &j)) > 0) {
110✔
204
                if (!streq(j->sp_namp, "root"))
110✔
205
                        continue;
×
206

207
                bool unprovisioned = streq_ptr(j->sp_pwdp, PASSWORD_UNPROVISIONED);
110✔
208
                log_debug("Root account found, %s.",
214✔
209
                          unprovisioned ? "with unprovisioned password, treating root as not configured" :
210
                                          "treating root as configured");
211
                return unprovisioned;
110✔
212
        }
UNCOV
213
        if (r < 0)
×
214
                return log_error_errno(r, "Failed to read shadow: %m");
×
215
        assert(r == 0);
×
UNCOV
216
        log_debug("No root account found in shadow, assuming root is not configured.");
×
217
        return true;
218
}
219

220
static int locale_is_ok(const char *name, void *userdata) {
11✔
221
        int rfd = ASSERT_FD(PTR_TO_FD(userdata)), r;
11✔
222

223
        r = dir_fd_is_root(rfd);
11✔
224
        if (r < 0)
11✔
UNCOV
225
                log_debug_errno(r, "Unable to determine if operating on host root directory, assuming we are: %m");
×
226

227
        return r != 0 ? locale_is_installed(name) > 0 : locale_is_valid(name);
11✔
228
}
229

230
static int prompt_locale(int rfd) {
11✔
UNCOV
231
        _cleanup_strv_free_ char **locales = NULL;
×
232
        bool acquired_from_creds = false;
11✔
233
        int r;
11✔
234

235
        assert(rfd >= 0);
11✔
236

237
        if (arg_locale || arg_locale_messages)
11✔
238
                return 0;
239

240
        r = read_credential("firstboot.locale", (void**) &arg_locale, NULL);
6✔
241
        if (r < 0)
6✔
242
                log_debug_errno(r, "Failed to read credential firstboot.locale, ignoring: %m");
5✔
243
        else
244
                acquired_from_creds = true;
245

246
        r = read_credential("firstboot.locale-messages", (void**) &arg_locale_messages, NULL);
6✔
247
        if (r < 0)
6✔
248
                log_debug_errno(r, "Failed to read credential firstboot.locale-messages, ignoring: %m");
5✔
249
        else
250
                acquired_from_creds = true;
251

252
        if (acquired_from_creds) {
5✔
253
                log_debug("Acquired locale from credentials.");
1✔
254
                return 0;
1✔
255
        }
256

257
        if (!arg_prompt_locale) {
5✔
258
                log_debug("Prompting for locale was not requested.");
4✔
259
                return 0;
4✔
260
        }
261

262
        r = get_locales(&locales);
1✔
263
        if (r < 0)
1✔
UNCOV
264
                return log_error_errno(r, "Cannot query locales list: %m");
×
265

266
        if (strv_isempty(locales))
1✔
UNCOV
267
                log_debug("No locales found, skipping locale selection.");
×
268
        else if (strv_length(locales) == 1) {
1✔
269

UNCOV
270
                if (streq(locales[0], SYSTEMD_DEFAULT_LOCALE))
×
UNCOV
271
                        log_debug("Only installed locale is default locale anyway, not setting locale explicitly.");
×
272
                else {
UNCOV
273
                        log_debug("Only a single locale available (%s), selecting it as default.", locales[0]);
×
274

UNCOV
275
                        arg_locale = strdup(locales[0]);
×
276
                        if (!arg_locale)
×
UNCOV
277
                                return log_oom();
×
278

279
                        /* Not setting arg_locale_message here, since it defaults to LANG anyway */
280
                }
281
        } else {
282
                print_welcome(rfd);
1✔
283

284
                r = prompt_loop("Please enter the new system locale name or number",
2✔
285
                                GLYPH_WORLD,
286
                                locales,
287
                                /* accepted= */ NULL,
288
                                /* ellipsize_percentage= */ 60,
289
                                /* n_columns= */ 3,
290
                                /* column_width= */ 20,
291
                                locale_is_ok,
292
                                /* refresh= */ NULL,
293
                                FD_TO_PTR(rfd),
1✔
294
                                PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
295
                                &arg_locale);
296
                if (r < 0)
1✔
297
                        return r;
298
                if (isempty(arg_locale))
12✔
299
                        return 0;
300

301
                r = prompt_loop("Please enter the new system message locale name or number",
1✔
302
                                GLYPH_WORLD,
303
                                locales,
304
                                /* accepted= */ NULL,
305
                                /* ellipsize_percentage= */ 60,
306
                                /* n_columns= */ 3,
307
                                /* column_width= */ 20,
308
                                locale_is_ok,
309
                                /* refresh= */ NULL,
310
                                FD_TO_PTR(rfd),
311
                                PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
312
                                &arg_locale_messages);
313
                if (r < 0)
1✔
314
                        return r;
315

316
                /* Suppress the messages setting if it's the same as the main locale anyway */
317
                if (streq_ptr(arg_locale, arg_locale_messages))
1✔
UNCOV
318
                        arg_locale_messages = mfree(arg_locale_messages);
×
319
        }
320

321
        return 0;
322
}
323

324
static int process_locale(int rfd) {
138✔
325
        _cleanup_close_ int pfd = -EBADF;
138✔
326
        _cleanup_free_ char *f = NULL;
138✔
327
        char* locales[3];
138✔
328
        unsigned i = 0;
138✔
329
        int r;
138✔
330

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

333
        pfd = chase_and_open_parent_at(rfd, etc_locale_conf(),
138✔
334
                                       CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
335
                                       &f);
336
        if (pfd < 0)
138✔
UNCOV
337
                return log_error_errno(pfd, "Failed to chase /etc/locale.conf: %m");
×
338

339
        r = should_configure(pfd, f);
138✔
340
        if (r == 0)
138✔
341
                log_debug("Found /etc/locale.conf, assuming locale information has been configured.");
124✔
342
        if (r <= 0)
138✔
343
                return r;
344

345
        r = dir_fd_is_root(rfd);
14✔
346
        if (r < 0)
14✔
UNCOV
347
                return log_error_errno(r, "Failed to check if directory file descriptor is root: %m");
×
348

349
        if (arg_copy_locale && r == 0) {
14✔
350
                r = copy_file_atomic_at(AT_FDCWD, etc_locale_conf(), pfd, f, 0644, COPY_REFLINK);
3✔
351
                if (r != -ENOENT) {
3✔
352
                        if (r < 0)
3✔
UNCOV
353
                                return log_error_errno(r, "Failed to copy host's /etc/locale.conf: %m");
×
354

355
                        log_info("Copied host's /etc/locale.conf.");
3✔
356
                        return 0;
3✔
357
                }
358
        }
359

360
        r = prompt_locale(rfd);
11✔
361
        if (r < 0)
11✔
362
                return r;
363

364
        if (!isempty(arg_locale))
11✔
365
                locales[i++] = strjoina("LANG=", arg_locale);
30✔
366
        if (!isempty(arg_locale_messages) && !streq_ptr(arg_locale_messages, arg_locale))
16✔
367
                locales[i++] = strjoina("LC_MESSAGES=", arg_locale_messages);
25✔
368

369
        if (i == 0)
11✔
370
                return 0;
371

372
        locales[i] = NULL;
7✔
373

374
        r = write_env_file(
7✔
375
                        pfd,
376
                        f,
377
                        /* headers= */ NULL,
378
                        locales,
379
                        WRITE_ENV_FILE_LABEL);
380
        if (r < 0)
7✔
UNCOV
381
                return log_error_errno(r, "Failed to write /etc/locale.conf: %m");
×
382

383
        log_info("/etc/locale.conf written.");
7✔
384
        return 1;
385
}
386

387
static int keymap_is_ok(const char* name, void *userdata) {
5✔
388
        int rfd = ASSERT_FD(PTR_TO_FD(userdata)), r;
5✔
389

390
        r = dir_fd_is_root(rfd);
5✔
391
        if (r < 0)
5✔
UNCOV
392
                log_debug_errno(r, "Unable to determine if operating on host root directory, assuming we are: %m");
×
393

394
        return r != 0 ? keymap_exists(name) > 0 : keymap_is_valid(name);
5✔
395
}
396

397
static int prompt_keymap(int rfd) {
13✔
398
        _cleanup_strv_free_ char **kmaps = NULL;
13✔
399
        int r;
13✔
400

401
        assert(rfd >= 0);
13✔
402

403
        if (arg_keymap)
13✔
404
                return 0;
405

406
        r = read_credential("firstboot.keymap", (void**) &arg_keymap, NULL);
10✔
407
        if (r < 0)
10✔
408
                log_debug_errno(r, "Failed to read credential firstboot.keymap, ignoring: %m");
9✔
409
        else {
410
                log_debug("Acquired keymap from credential.");
1✔
411
                return 0;
1✔
412
        }
413

414
        if (!arg_prompt_keymap) {
9✔
415
                log_debug("Prompting for keymap was not requested.");
8✔
416
                return 0;
8✔
417
        }
418

419
        r = get_keymaps(&kmaps);
1✔
420
        if (r == -ENOENT) /* no keymaps installed */
1✔
UNCOV
421
                return log_debug_errno(r, "No keymaps are installed.");
×
422
        if (r < 0)
1✔
UNCOV
423
                return log_error_errno(r, "Failed to read keymaps: %m");
×
424

425
        print_welcome(rfd);
1✔
426

427
        return prompt_loop(
1✔
428
                        "Please enter the new keymap name or number",
429
                        GLYPH_KEYBOARD,
430
                        kmaps,
431
                        /* accepted= */ NULL,
432
                        /* ellipsize_percentage= */ 60,
433
                        /* n_columns= */ 3,
434
                        /* column_width= */ 20,
435
                        keymap_is_ok,
436
                        /* refresh= */ NULL,
437
                        FD_TO_PTR(rfd),
1✔
438
                        PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
439
                        &arg_keymap);
440
}
441

442
static int process_keymap(int rfd) {
138✔
443
        _cleanup_close_ int pfd = -EBADF;
138✔
444
        _cleanup_free_ char *f = NULL;
138✔
UNCOV
445
        _cleanup_strv_free_ char **keymap = NULL;
×
446
        int r;
138✔
447

448
        assert(rfd >= 0);
138✔
449

450
        pfd = chase_and_open_parent_at(rfd, etc_vconsole_conf(),
138✔
451
                                       CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
452
                                       &f);
453
        if (pfd < 0)
138✔
UNCOV
454
                return log_error_errno(pfd, "Failed to chase /etc/vconsole.conf: %m");
×
455

456
        r = should_configure(pfd, f);
138✔
457
        if (r == 0)
138✔
458
                log_debug("Found /etc/vconsole.conf, assuming console has been configured.");
122✔
459
        if (r <= 0)
138✔
460
                return r;
461

462
        r = dir_fd_is_root(rfd);
16✔
463
        if (r < 0)
16✔
UNCOV
464
                return log_error_errno(r, "Failed to check if directory file descriptor is root: %m");
×
465

466
        if (arg_copy_keymap && r == 0) {
16✔
467
                r = copy_file_atomic_at(AT_FDCWD, etc_vconsole_conf(), pfd, f, 0644, COPY_REFLINK);
3✔
468
                if (r != -ENOENT) {
3✔
469
                        if (r < 0)
3✔
UNCOV
470
                                return log_error_errno(r, "Failed to copy host's /etc/vconsole.conf: %m");
×
471

472
                        log_info("Copied host's /etc/vconsole.conf.");
3✔
473
                        return 0;
3✔
474
                }
475
        }
476

477
        r = prompt_keymap(rfd);
13✔
478
        if (r == -ENOENT)
13✔
479
                return 0; /* don't fail if no keymaps are installed */
480
        if (r < 0)
13✔
481
                return r;
482

483
        if (isempty(arg_keymap))
143✔
484
                return 0;
485

486
        VCContext vc = {
5✔
487
                .keymap = arg_keymap,
488
        };
489
        _cleanup_(x11_context_clear) X11Context xc = {};
5✔
490

491
        r = vconsole_convert_to_x11(&vc, /* verify= */ NULL, &xc);
5✔
492
        if (r < 0)
5✔
UNCOV
493
                return log_error_errno(r, "Failed to convert keymap data: %m");
×
494

495
        r = vconsole_serialize(&vc, &xc, &keymap);
5✔
496
        if (r < 0)
5✔
UNCOV
497
                return log_error_errno(r, "Failed to serialize keymap data: %m");
×
498

499
        r = write_vconsole_conf(pfd, f, keymap);
5✔
500
        if (r < 0)
5✔
UNCOV
501
                return log_error_errno(r, "Failed to write /etc/vconsole.conf: %m");
×
502

503
        log_info("/etc/vconsole.conf written.");
5✔
504
        return 1;
505
}
506

507
static int timezone_is_ok(const char *name, void *userdata) {
1✔
508
        return timezone_is_valid(name, LOG_DEBUG);
1✔
509
}
510

511
static int prompt_timezone(int rfd) {
119✔
512
        _cleanup_strv_free_ char **zones = NULL;
119✔
513
        int r;
119✔
514

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

517
        if (arg_timezone)
119✔
518
                return 0;
519

520
        r = read_credential("firstboot.timezone", (void**) &arg_timezone, NULL);
116✔
521
        if (r < 0)
116✔
522
                log_debug_errno(r, "Failed to read credential firstboot.timezone, ignoring: %m");
11✔
523
        else {
524
                log_debug("Acquired timezone from credential.");
105✔
525
                return 0;
105✔
526
        }
527

528
        if (!arg_prompt_timezone) {
11✔
529
                log_debug("Prompting for timezone was not requested.");
10✔
530
                return 0;
10✔
531
        }
532

533
        r = get_timezones(&zones);
1✔
534
        if (r < 0)
1✔
UNCOV
535
                return log_error_errno(r, "Cannot query timezone list: %m");
×
536

537
        print_welcome(rfd);
1✔
538

539
        return prompt_loop(
1✔
540
                        "Please enter the new timezone name or number",
541
                        GLYPH_CLOCK,
542
                        zones,
543
                        /* accepted= */ NULL,
544
                        /* ellipsize_percentage= */ 30,
545
                        /* n_columns= */ 3,
546
                        /* column_width= */ 20,
547
                        timezone_is_ok,
548
                        /* refresh= */ NULL,
549
                        FD_TO_PTR(rfd),
1✔
550
                        PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
551
                        &arg_timezone);
552
}
553

554
static int process_timezone(int rfd) {
138✔
555
        _cleanup_close_ int pfd = -EBADF;
138✔
556
        _cleanup_free_ char *f = NULL, *relpath = NULL;
138✔
557
        const char *e;
138✔
558
        int r;
138✔
559

560
        assert(rfd >= 0);
138✔
561

562
        pfd = chase_and_open_parent_at(rfd, etc_localtime(),
138✔
563
                                       CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
564
                                       &f);
565
        if (pfd < 0)
138✔
UNCOV
566
                return log_error_errno(pfd, "Failed to chase /etc/localtime: %m");
×
567

568
        r = should_configure(pfd, f);
138✔
569
        if (r == 0)
138✔
570
                log_debug("Found /etc/localtime, assuming timezone has been configured.");
16✔
571
        if (r <= 0)
138✔
572
                return r;
573

574
        r = dir_fd_is_root(rfd);
122✔
575
        if (r < 0)
122✔
UNCOV
576
                return log_error_errno(r, "Failed to check if directory file descriptor is root: %m");
×
577

578
        if (arg_copy_timezone && r == 0) {
122✔
579
                _cleanup_free_ char *s = NULL;
3✔
580

581
                r = readlink_malloc(etc_localtime(), &s);
3✔
582
                if (r != -ENOENT) {
3✔
583
                        if (r < 0)
3✔
UNCOV
584
                                return log_error_errno(r, "Failed to read host's /etc/localtime: %m");
×
585

586
                        r = symlinkat_atomic_full(s, pfd, f, SYMLINK_LABEL);
3✔
587
                        if (r < 0)
3✔
UNCOV
588
                                return log_error_errno(r, "Failed to create /etc/localtime symlink: %m");
×
589

590
                        log_info("Copied host's /etc/localtime.");
3✔
591
                        return 0;
3✔
592
                }
593
        }
594

595
        r = prompt_timezone(rfd);
119✔
596
        if (r < 0)
119✔
597
                return r;
598

599
        if (isempty(arg_timezone))
247✔
600
                return 0;
601

602
        e = strjoina("/usr/share/zoneinfo/", arg_timezone);
545✔
603
        r = path_make_relative_parent(etc_localtime(), e, &relpath);
109✔
604
        if (r < 0)
109✔
605
                return r;
606

607
        r = symlinkat_atomic_full(relpath, pfd, f, SYMLINK_LABEL);
109✔
608
        if (r < 0)
109✔
UNCOV
609
                return log_error_errno(r, "Failed to create /etc/localtime symlink: %m");
×
610

611
        log_info("/etc/localtime written");
109✔
612
        return 0;
613
}
614

615
static int hostname_is_ok(const char *name, void *userdata) {
1✔
616
        return hostname_is_valid(name, VALID_HOSTNAME_TRAILING_DOT);
1✔
617
}
618

619
static int prompt_hostname(int rfd) {
124✔
620
        int r;
124✔
621

622
        assert(rfd >= 0);
124✔
623

624
        if (arg_hostname)
124✔
625
                return 0;
626

627
        if (!arg_prompt_hostname) {
120✔
628
                log_debug("Prompting for hostname was not requested.");
119✔
629
                return 0;
119✔
630
        }
631

632
        print_welcome(rfd);
1✔
633

634
        r = prompt_loop("Please enter the new hostname",
2✔
635
                        GLYPH_LABEL,
636
                        /* menu= */ NULL,
637
                        /* accepted= */ NULL,
638
                        /* ellipsize_percentage= */ 100,
639
                        /* n_columns= */ 3,
640
                        /* column_width= */ 20,
641
                        hostname_is_ok,
642
                        /* refresh= */ NULL,
643
                        FD_TO_PTR(rfd),
1✔
644
                        PROMPT_MAY_SKIP,
645
                        &arg_hostname);
646
        if (r < 0)
1✔
647
                return r;
648

649
        if (arg_hostname)
1✔
650
                hostname_cleanup(arg_hostname);
1✔
651

652
        return 0;
653
}
654

655
static int process_hostname(int rfd) {
138✔
656
        _cleanup_close_ int pfd = -EBADF;
138✔
657
        _cleanup_free_ char *f = NULL;
138✔
658
        int r;
138✔
659

660
        assert(rfd >= 0);
138✔
661

662
        pfd = chase_and_open_parent_at(rfd, etc_hostname(),
138✔
663
                                       CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN,
664
                                       &f);
665
        if (pfd < 0)
138✔
UNCOV
666
                return log_error_errno(pfd, "Failed to chase /etc/hostname: %m");
×
667

668
        r = should_configure(pfd, f);
138✔
669
        if (r == 0)
138✔
670
                log_debug("Found /etc/hostname, assuming hostname has been configured.");
14✔
671
        if (r <= 0)
138✔
672
                return r;
673

674
        r = prompt_hostname(rfd);
124✔
675
        if (r < 0)
124✔
676
                return r;
677

678
        if (isempty(arg_hostname))
143✔
679
                return 0;
680

681
        r = write_string_file_at(pfd, f, arg_hostname,
5✔
682
                                 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
683
        if (r < 0)
5✔
UNCOV
684
                return log_error_errno(r, "Failed to write /etc/hostname: %m");
×
685

686
        log_info("/etc/hostname written.");
5✔
687
        return 0;
688
}
689

690
static int process_machine_id(int rfd) {
138✔
691
        _cleanup_close_ int pfd = -EBADF;
138✔
692
        _cleanup_free_ char *f = NULL;
138✔
693
        int r;
138✔
694

695
        assert(rfd >= 0);
138✔
696

697
        pfd = chase_and_open_parent_at(rfd, "/etc/machine-id",
138✔
698
                                       CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
699
                                       &f);
700
        if (pfd < 0)
138✔
UNCOV
701
                return log_error_errno(pfd, "Failed to chase /etc/machine-id: %m");
×
702

703
        r = should_configure(pfd, f);
138✔
704
        if (r == 0)
138✔
705
                log_debug("Found /etc/machine-id, assuming machine-id has been configured.");
114✔
706
        if (r <= 0)
138✔
707
                return r;
708

709
        if (sd_id128_is_null(arg_machine_id)) {
24✔
710
                log_debug("Initialization of machine-id was not requested, skipping.");
21✔
711
                return 0;
21✔
712
        }
713

714
        r = write_string_file_at(pfd, "machine-id", SD_ID128_TO_STRING(arg_machine_id),
3✔
715
                                 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
716
        if (r < 0)
3✔
UNCOV
717
                return log_error_errno(r, "Failed to write /etc/machine-id: %m");
×
718

719
        log_info("/etc/machine-id written.");
3✔
720
        return 0;
721
}
722

723
static int prompt_root_password(int rfd) {
29✔
724
        const char *msg1, *msg2;
29✔
725
        int r;
29✔
726

727
        assert(rfd >= 0);
29✔
728

729
        if (arg_root_password)
29✔
730
                return 0;
731

732
        if (get_credential_user_password("root", &arg_root_password, &arg_root_password_is_hashed) >= 0)
20✔
733
                return 0;
734

735
        if (!arg_prompt_root_password) {
19✔
736
                log_debug("Prompting for root password was not requested.");
18✔
737
                return 0;
18✔
738
        }
739

740
        print_welcome(rfd);
1✔
741

742
        msg1 = strjoina("Please enter the new root password (empty to skip):");
3✔
743
        msg2 = strjoina("Please enter the new root password again:");
3✔
744

745
        suggest_passwords();
1✔
746

UNCOV
747
        for (;;) {
×
748
                _cleanup_strv_free_erase_ char **a = NULL, **b = NULL;
1✔
749
                _cleanup_free_ char *error = NULL;
1✔
750

751
                AskPasswordRequest req = {
1✔
752
                        .tty_fd = -EBADF,
753
                        .message = msg1,
754
                        .until = USEC_INFINITY,
755
                        .hup_fd = -EBADF,
756
                };
757

758
                r = ask_password_tty(&req, /* flags= */ 0, &a);
1✔
759
                if (r < 0)
1✔
UNCOV
760
                        return log_error_errno(r, "Failed to query root password: %m");
×
761
                if (strv_length(a) != 1)
1✔
UNCOV
762
                        return log_error_errno(SYNTHETIC_ERRNO(EIO),
×
763
                                               "Received multiple passwords, where we expected one.");
764

765
                if (isempty(*a)) {
1✔
766
                        log_info("No password entered, skipping.");
1✔
767
                        break;
768
                }
769

UNCOV
770
                r = check_password_quality(*a, /* old = */ NULL, "root", &error);
×
UNCOV
771
                if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
×
UNCOV
772
                        log_warning("Password quality check is not supported, proceeding anyway.");
×
UNCOV
773
                else if (r < 0)
×
774
                        return log_error_errno(r, "Failed to check password quality: %m");
×
UNCOV
775
                else if (r == 0)
×
UNCOV
776
                        log_warning("Password is weak, accepting anyway: %s", error);
×
777

UNCOV
778
                req.message = msg2;
×
779

UNCOV
780
                r = ask_password_tty(&req, /* flags= */ 0, &b);
×
UNCOV
781
                if (r < 0)
×
UNCOV
782
                        return log_error_errno(r, "Failed to query root password: %m");
×
UNCOV
783
                if (strv_length(b) != 1)
×
UNCOV
784
                        return log_error_errno(SYNTHETIC_ERRNO(EIO),
×
785
                                               "Received multiple passwords, where we expected one.");
786

UNCOV
787
                if (!streq(*a, *b)) {
×
UNCOV
788
                        log_error("Entered passwords did not match, please try again.");
×
UNCOV
789
                        continue;
×
790
                }
791

UNCOV
792
                arg_root_password = TAKE_PTR(*a);
×
UNCOV
793
                break;
×
794
        }
795

796
        return 0;
1✔
797
}
798

799
static int find_shell(int rfd, const char *path) {
7✔
800
        int r;
7✔
801

802
        assert(path);
7✔
803

804
        if (!valid_shell(path))
7✔
UNCOV
805
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "%s is not a valid shell", path);
×
806

807
        r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT, NULL, NULL);
7✔
808
        if (r < 0)
7✔
809
                return log_error_errno(r, "Failed to resolve shell %s: %m", path);
1✔
810

811
        return 0;
812
}
813

814
static int shell_is_ok(const char *path, void *userdata) {
2✔
815
        int rfd = ASSERT_FD(PTR_TO_FD(userdata));
2✔
816

817
        return find_shell(rfd, path) >= 0;
2✔
818
}
819

820
static int prompt_root_shell(int rfd) {
29✔
821
        int r;
29✔
822

823
        assert(rfd >= 0);
29✔
824

825
        if (arg_root_shell)
29✔
826
                return 0;
827

828
        r = read_credential("passwd.shell.root", (void**) &arg_root_shell, NULL);
24✔
829
        if (r < 0)
24✔
830
                log_debug_errno(r, "Failed to read credential passwd.shell.root, ignoring: %m");
23✔
831
        else {
832
                log_debug("Acquired root shell from credential.");
1✔
833
                return 0;
1✔
834
        }
835

836
        if (!arg_prompt_root_shell) {
23✔
837
                log_debug("Prompting for root shell was not requested.");
21✔
838
                return 0;
21✔
839
        }
840

841
        print_welcome(rfd);
2✔
842

843
        return prompt_loop(
2✔
844
                        "Please enter the new root shell",
845
                        GLYPH_SHELL,
846
                        /* menu= */ NULL,
847
                        /* accepted= */ NULL,
848
                        /* ellipsize_percentage= */ 0,
849
                        /* n_columns= */ 3,
850
                        /* column_width= */ 20,
851
                        shell_is_ok,
852
                        /* refresh= */ NULL,
853
                        FD_TO_PTR(rfd),
2✔
854
                        PROMPT_MAY_SKIP,
855
                        &arg_root_shell);
856
}
857

858
static int write_root_passwd(int rfd, int etc_fd, const char *password, const char *shell) {
15✔
859
        _cleanup_fclose_ FILE *original = NULL, *passwd = NULL;
15✔
860
        _cleanup_(unlink_and_freep) char *passwd_tmp = NULL;
15✔
861
        int r;
15✔
862
        bool found = false;
15✔
863

864
        r = fopen_temporary_at_label(etc_fd, "passwd", "passwd", &passwd, &passwd_tmp);
15✔
865
        if (r < 0)
15✔
866
                return r;
867

868
        r = xfopenat(etc_fd, "passwd", "re", O_NOFOLLOW, &original);
15✔
869
        if (r < 0 && r != -ENOENT)
15✔
870
                return r;
871

872
        if (original) {
15✔
873
                struct passwd *i;
4✔
874

875
                r = copy_rights(fileno(original), fileno(passwd));
4✔
876
                if (r < 0)
4✔
UNCOV
877
                        return r;
×
878

879
                while ((r = fgetpwent_sane(original, &i)) > 0) {
7✔
880

881
                        if (streq(i->pw_name, "root")) {
3✔
882
                                if (password)
3✔
883
                                        i->pw_passwd = (char *) password;
2✔
884
                                if (shell)
3✔
885
                                        i->pw_shell = (char *) shell;
2✔
886
                                found = true;
887
                        }
888

889
                        r = putpwent_sane(i, passwd);
3✔
890
                        if (r < 0)
3✔
891
                                return r;
892
                }
893
                if (r < 0)
4✔
894
                        return r;
895

896
        } else {
897
                r = fchmod(fileno(passwd), 0644);
11✔
898
                if (r < 0)
11✔
UNCOV
899
                        return -errno;
×
900
        }
901

902
        if (!found) {
4✔
903
                struct passwd root = {
12✔
904
                        .pw_name = (char *) "root",
905
                        .pw_passwd = (char *) (password ?: PASSWORD_SEE_SHADOW),
12✔
906
                        .pw_uid = 0,
907
                        .pw_gid = 0,
908
                        .pw_gecos = (char *) "Super User",
909
                        .pw_dir = (char *) "/root",
910
                        .pw_shell = (char *) (shell ?: default_root_shell_at(rfd)),
6✔
911
                };
912

913
                if (errno != ENOENT)
12✔
UNCOV
914
                        return -errno;
×
915

916
                r = putpwent_sane(&root, passwd);
12✔
917
                if (r < 0)
12✔
918
                        return r;
919
        }
920

921
        r = fflush_sync_and_check(passwd);
15✔
922
        if (r < 0)
15✔
923
                return r;
924

925
        r = renameat_and_apply_smack_floor_label(etc_fd, passwd_tmp, etc_fd, "passwd");
15✔
926
        if (r < 0)
15✔
UNCOV
927
                return r;
×
928

929
        return 0;
930
}
931

932
static int write_root_shadow(int etc_fd, const char *hashed_password) {
15✔
933
        _cleanup_fclose_ FILE *original = NULL, *shadow = NULL;
15✔
934
        _cleanup_(unlink_and_freep) char *shadow_tmp = NULL;
15✔
935
        int r;
15✔
936
        bool found = false;
15✔
937

938
        r = fopen_temporary_at_label(etc_fd, "shadow", "shadow", &shadow, &shadow_tmp);
15✔
939
        if (r < 0)
15✔
940
                return r;
941

942
        r = xfopenat(etc_fd, "shadow", "re", O_NOFOLLOW, &original);
15✔
943
        if (r < 0 && r != -ENOENT)
15✔
944
                return r;
945

946
        if (original) {
15✔
947
                struct spwd *i;
4✔
948

949
                r = copy_rights(fileno(original), fileno(shadow));
4✔
950
                if (r < 0)
4✔
UNCOV
951
                        return r;
×
952

953
                while ((r = fgetspent_sane(original, &i)) > 0) {
7✔
954

955
                        if (streq(i->sp_namp, "root")) {
3✔
956
                                if (hashed_password) {
3✔
957
                                        i->sp_pwdp = (char *) hashed_password;
2✔
958
                                        i->sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
2✔
959
                                }
960
                                found = true;
961
                        }
962

963
                        r = putspent_sane(i, shadow);
3✔
964
                        if (r < 0)
3✔
965
                                return r;
966
                }
967
                if (r < 0)
4✔
968
                        return r;
969

970
        } else {
971
                r = fchmod(fileno(shadow), 0000);
11✔
972
                if (r < 0)
11✔
973
                        return -errno;
×
974
        }
975

976
        if (!found) {
4✔
977
                struct spwd root = {
36✔
978
                        .sp_namp = (char*) "root",
979
                        .sp_pwdp = (char *) (hashed_password ?: PASSWORD_LOCKED_AND_INVALID),
12✔
980
                        .sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY),
12✔
981
                        .sp_min = -1,
982
                        .sp_max = -1,
983
                        .sp_warn = -1,
984
                        .sp_inact = -1,
985
                        .sp_expire = -1,
986
                        .sp_flag = ULONG_MAX, /* this appears to be what everybody does ... */
987
                };
988

989
                if (errno != ENOENT)
12✔
UNCOV
990
                        return -errno;
×
991

992
                r = putspent_sane(&root, shadow);
12✔
993
                if (r < 0)
12✔
994
                        return r;
995
        }
996

997
        r = fflush_sync_and_check(shadow);
15✔
998
        if (r < 0)
15✔
999
                return r;
1000

1001
        r = renameat_and_apply_smack_floor_label(etc_fd, shadow_tmp, etc_fd, "shadow");
15✔
1002
        if (r < 0)
15✔
UNCOV
1003
                return r;
×
1004

1005
        return 0;
1006
}
1007

1008
static int process_root_account(int rfd) {
138✔
1009
        _cleanup_close_ int pfd = -EBADF;
138✔
UNCOV
1010
        _cleanup_(release_lock_file) LockFile lock = LOCK_FILE_INIT;
×
1011
        _cleanup_(erase_and_freep) char *_hashed_password = NULL;
138✔
1012
        const char *password, *hashed_password;
138✔
1013
        int k = 0, r;
138✔
1014

1015
        assert(rfd >= 0);
138✔
1016

1017
        pfd = chase_and_open_parent_at(rfd, "/etc/passwd",
138✔
1018
                                       CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
1019
                                       NULL);
1020
        if (pfd < 0)
138✔
UNCOV
1021
                return log_error_errno(pfd, "Failed to chase /etc/passwd: %m");
×
1022

1023
        /* Ensure that passwd and shadow are in the same directory and are not symlinks. */
1024

1025
        FOREACH_STRING(s, "passwd", "shadow") {
414✔
1026
                r = verify_regular_at(pfd, s, /* follow = */ false);
276✔
1027
                if (r < 0 && r != -ENOENT)
276✔
UNCOV
1028
                        return log_error_errno(r, "Verification of /etc/%s being regular file failed: %m", s);
×
1029

1030
                r = should_configure(pfd, s);
276✔
1031
                if (r < 0)
276✔
1032
                        return r;
1033

1034
                k += r;
276✔
1035
        }
1036

1037
        if (k == 0) {
138✔
1038
                log_debug("Found /etc/passwd and /etc/shadow, assuming root account has been initialized.");
109✔
1039
                return 0;
109✔
1040
        }
1041

1042
        r = make_lock_file_at(pfd, ETC_PASSWD_LOCK_FILENAME, LOCK_EX, &lock);
29✔
1043
        if (r < 0)
29✔
UNCOV
1044
                return log_error_errno(r, "Failed to take a lock on /etc/passwd: %m");
×
1045

1046
        k = dir_fd_is_root(rfd);
29✔
1047
        if (k < 0)
29✔
UNCOV
1048
                return log_error_errno(k, "Failed to check if directory file descriptor is root: %m");
×
1049

1050
        if (arg_copy_root_shell && k == 0) {
29✔
1051
                _cleanup_free_ struct passwd *p = NULL;
2✔
1052

1053
                r = getpwnam_malloc("root", &p);
2✔
1054
                if (r < 0)
2✔
UNCOV
1055
                        return log_error_errno(r, "Failed to find passwd entry for root: %m");
×
1056

1057
                r = free_and_strdup(&arg_root_shell, p->pw_shell);
2✔
1058
                if (r < 0)
2✔
UNCOV
1059
                        return log_oom();
×
1060
        }
1061

1062
        r = prompt_root_shell(rfd);
29✔
1063
        if (r < 0)
29✔
1064
                return r;
1065

1066
        if (arg_copy_root_password && k == 0) {
29✔
1067
                struct spwd *p;
2✔
1068

1069
                errno = 0;
2✔
1070
                p = getspnam("root");
2✔
1071
                if (!p)
2✔
UNCOV
1072
                        return log_error_errno(errno_or_else(EIO), "Failed to find shadow entry for root: %m");
×
1073

1074
                r = free_and_strdup(&arg_root_password, p->sp_pwdp);
2✔
1075
                if (r < 0)
2✔
UNCOV
1076
                        return log_oom();
×
1077

1078
                arg_root_password_is_hashed = true;
2✔
1079
        }
1080

1081
        r = prompt_root_password(rfd);
29✔
1082
        if (r < 0)
29✔
1083
                return r;
1084

1085
        if (arg_root_password && arg_root_password_is_hashed) {
29✔
1086
                password = PASSWORD_SEE_SHADOW;
1087
                hashed_password = arg_root_password;
1088
        } else if (arg_root_password) {
23✔
1089
                r = hash_password(arg_root_password, &_hashed_password);
4✔
1090
                if (r < 0)
4✔
UNCOV
1091
                        return log_error_errno(r, "Failed to hash password: %m");
×
1092

1093
                password = PASSWORD_SEE_SHADOW;
4✔
1094
                hashed_password = _hashed_password;
4✔
1095

1096
        } else if (arg_delete_root_password) {
19✔
1097
                password = PASSWORD_SEE_SHADOW;
1098
                hashed_password = PASSWORD_NONE;
1099
        } else if (!arg_root_password && arg_prompt_root_password) {
18✔
1100
                /* If the user was prompted, but no password was supplied, lock the account. */
1101
                password = PASSWORD_SEE_SHADOW;
1102
                hashed_password = PASSWORD_LOCKED_AND_INVALID;
1103
        } else
1104
                /* Leave the password as is. */
1105
                password = hashed_password = NULL;
17✔
1106

1107
        /* Don't create/modify passwd and shadow if there's nothing to do. */
1108
        if (!(password || hashed_password || arg_root_shell)) {
29✔
1109
                log_debug("Initialization of root account was not requested, skipping.");
14✔
1110
                return 0;
14✔
1111
        }
1112

1113
        r = write_root_passwd(rfd, pfd, password, arg_root_shell);
15✔
1114
        if (r < 0)
15✔
UNCOV
1115
                return log_error_errno(r, "Failed to write /etc/passwd: %m");
×
1116

1117
        log_info("/etc/passwd written.");
15✔
1118

1119
        r = write_root_shadow(pfd, hashed_password);
15✔
1120
        if (r < 0)
15✔
UNCOV
1121
                return log_error_errno(r, "Failed to write /etc/shadow: %m");
×
1122

1123
        log_info("/etc/shadow written.");
15✔
1124
        return 0;
1125
}
1126

1127
static int process_kernel_cmdline(int rfd) {
138✔
1128
        _cleanup_close_ int pfd = -EBADF;
138✔
1129
        _cleanup_free_ char *f = NULL;
138✔
1130
        int r;
138✔
1131

1132
        assert(rfd >= 0);
138✔
1133

1134
        pfd = chase_and_open_parent_at(rfd, "/etc/kernel/cmdline",
138✔
1135
                                       CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
1136
                                       &f);
1137
        if (pfd < 0)
138✔
UNCOV
1138
                return log_error_errno(pfd, "Failed to chase /etc/kernel/cmdline: %m");
×
1139

1140
        r = should_configure(pfd, f);
138✔
1141
        if (r == 0)
138✔
1142
                log_debug("Found /etc/kernel/cmdline, assuming kernel command line has been configured.");
1✔
1143
        if (r <= 0)
138✔
1144
                return r;
1145

1146
        if (!arg_kernel_cmdline) {
137✔
1147
                log_debug("Creation of /etc/kernel/cmdline was not requested, skipping.");
135✔
1148
                return 0;
135✔
1149
        }
1150

1151
        r = write_string_file_at(pfd, "cmdline", arg_kernel_cmdline,
2✔
1152
                                 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
1153
        if (r < 0)
2✔
UNCOV
1154
                return log_error_errno(r, "Failed to write /etc/kernel/cmdline: %m");
×
1155

1156
        log_info("/etc/kernel/cmdline written.");
2✔
1157
        return 0;
1158
}
1159

1160
static int reset_one(int rfd, const char *path) {
6✔
1161
        _cleanup_close_ int pfd = -EBADF;
6✔
1162
        _cleanup_free_ char *f = NULL;
6✔
1163

1164
        assert(rfd >= 0);
6✔
1165
        assert(path);
6✔
1166

1167
        pfd = chase_and_open_parent_at(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_WARN|CHASE_NOFOLLOW, &f);
6✔
1168
        if (pfd == -ENOENT)
6✔
1169
                return 0;
1170
        if (pfd < 0)
6✔
UNCOV
1171
                return log_error_errno(pfd, "Failed to resolve %s: %m", path);
×
1172

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

1176
        log_info("Removed %s", path);
6✔
1177
        return 0;
1178
}
1179

1180
static int process_reset(int rfd) {
138✔
1181
        int r;
138✔
1182

1183
        assert(rfd >= 0);
138✔
1184

1185
        if (!arg_reset)
138✔
1186
                return 0;
1187

1188
        FOREACH_STRING(p,
7✔
1189
                       etc_locale_conf(),
1190
                       etc_vconsole_conf(),
1191
                       etc_hostname(),
1192
                       "/etc/machine-id",
1193
                       "/etc/kernel/cmdline",
1194
                       etc_localtime()) {
1195
                r = reset_one(rfd, p);
6✔
1196
                if (r < 0)
6✔
UNCOV
1197
                        return r;
×
1198
        }
1199

1200
        return 0;
1✔
1201
}
1202

UNCOV
1203
static int help(void) {
×
UNCOV
1204
        _cleanup_free_ char *link = NULL;
×
UNCOV
1205
        int r;
×
1206

UNCOV
1207
        r = terminal_urlify_man("systemd-firstboot", "1", &link);
×
UNCOV
1208
        if (r < 0)
×
UNCOV
1209
                return log_oom();
×
1210

UNCOV
1211
        printf("%1$s [OPTIONS...]\n"
×
1212
               "\n%3$sConfigures basic settings of the system.%4$s\n\n"
1213
               "  -h --help                       Show this help\n"
1214
               "     --version                    Show package version\n"
1215
               "     --root=PATH                  Operate on an alternate filesystem root\n"
1216
               "     --image=PATH                 Operate on disk image as filesystem root\n"
1217
               "     --image-policy=POLICY        Specify disk image dissection policy\n"
1218
               "     --locale=LOCALE              Set primary locale (LANG=)\n"
1219
               "     --locale-messages=LOCALE     Set message locale (LC_MESSAGES=)\n"
1220
               "     --keymap=KEYMAP              Set keymap\n"
1221
               "     --timezone=TIMEZONE          Set timezone\n"
1222
               "     --hostname=NAME              Set hostname\n"
1223
               "     --setup-machine-id           Set a random machine ID\n"
1224
               "     --machine-id=ID              Set specified machine ID\n"
1225
               "     --root-password=PASSWORD     Set root password from plaintext password\n"
1226
               "     --root-password-file=FILE    Set root password from file\n"
1227
               "     --root-password-hashed=HASH  Set root password from hashed password\n"
1228
               "     --root-shell=SHELL           Set root shell\n"
1229
               "     --kernel-command-line=CMDLINE\n"
1230
               "                                  Set kernel command line\n"
1231
               "     --prompt-locale              Prompt the user for locale settings\n"
1232
               "     --prompt-keymap              Prompt the user for keymap settings\n"
1233
               "     --prompt-timezone            Prompt the user for timezone\n"
1234
               "     --prompt-hostname            Prompt the user for hostname\n"
1235
               "     --prompt-root-password       Prompt the user for root password\n"
1236
               "     --prompt-root-shell          Prompt the user for root shell\n"
1237
               "     --prompt                     Prompt for all of the above\n"
1238
               "     --copy-locale                Copy locale from host\n"
1239
               "     --copy-keymap                Copy keymap from host\n"
1240
               "     --copy-timezone              Copy timezone from host\n"
1241
               "     --copy-root-password         Copy root password from host\n"
1242
               "     --copy-root-shell            Copy root shell from host\n"
1243
               "     --copy                       Copy locale, keymap, timezone, root password\n"
1244
               "     --force                      Overwrite existing files\n"
1245
               "     --delete-root-password       Delete root password\n"
1246
               "     --welcome=no                 Disable the welcome text\n"
1247
               "     --chrome=no                  Don't show color bar at top and bottom of\n"
1248
               "                                  terminal\n"
1249
               "     --reset                      Remove existing files\n"
1250
               "\nSee the %2$s for details.\n",
1251
               program_invocation_short_name,
1252
               link,
1253
               ansi_highlight(),
1254
               ansi_normal());
1255

1256
        return 0;
1257
}
1258

1259
static int parse_argv(int argc, char *argv[]) {
141✔
1260

1261
        enum {
141✔
1262
                ARG_VERSION = 0x100,
1263
                ARG_ROOT,
1264
                ARG_IMAGE,
1265
                ARG_IMAGE_POLICY,
1266
                ARG_LOCALE,
1267
                ARG_LOCALE_MESSAGES,
1268
                ARG_KEYMAP,
1269
                ARG_TIMEZONE,
1270
                ARG_HOSTNAME,
1271
                ARG_SETUP_MACHINE_ID,
1272
                ARG_MACHINE_ID,
1273
                ARG_ROOT_PASSWORD,
1274
                ARG_ROOT_PASSWORD_FILE,
1275
                ARG_ROOT_PASSWORD_HASHED,
1276
                ARG_ROOT_SHELL,
1277
                ARG_KERNEL_COMMAND_LINE,
1278
                ARG_PROMPT,
1279
                ARG_PROMPT_LOCALE,
1280
                ARG_PROMPT_KEYMAP,
1281
                ARG_PROMPT_TIMEZONE,
1282
                ARG_PROMPT_HOSTNAME,
1283
                ARG_PROMPT_ROOT_PASSWORD,
1284
                ARG_PROMPT_ROOT_SHELL,
1285
                ARG_COPY,
1286
                ARG_COPY_LOCALE,
1287
                ARG_COPY_KEYMAP,
1288
                ARG_COPY_TIMEZONE,
1289
                ARG_COPY_ROOT_PASSWORD,
1290
                ARG_COPY_ROOT_SHELL,
1291
                ARG_FORCE,
1292
                ARG_DELETE_ROOT_PASSWORD,
1293
                ARG_WELCOME,
1294
                ARG_CHROME,
1295
                ARG_RESET,
1296
        };
1297

1298
        static const struct option options[] = {
141✔
1299
                { "help",                    no_argument,       NULL, 'h'                         },
1300
                { "version",                 no_argument,       NULL, ARG_VERSION                 },
1301
                { "root",                    required_argument, NULL, ARG_ROOT                    },
1302
                { "image",                   required_argument, NULL, ARG_IMAGE                   },
1303
                { "image-policy",            required_argument, NULL, ARG_IMAGE_POLICY            },
1304
                { "locale",                  required_argument, NULL, ARG_LOCALE                  },
1305
                { "locale-messages",         required_argument, NULL, ARG_LOCALE_MESSAGES         },
1306
                { "keymap",                  required_argument, NULL, ARG_KEYMAP                  },
1307
                { "timezone",                required_argument, NULL, ARG_TIMEZONE                },
1308
                { "hostname",                required_argument, NULL, ARG_HOSTNAME                },
1309
                { "setup-machine-id",        no_argument,       NULL, ARG_SETUP_MACHINE_ID        },
1310
                { "machine-id",              required_argument, NULL, ARG_MACHINE_ID              },
1311
                { "root-password",           required_argument, NULL, ARG_ROOT_PASSWORD           },
1312
                { "root-password-file",      required_argument, NULL, ARG_ROOT_PASSWORD_FILE      },
1313
                { "root-password-hashed",    required_argument, NULL, ARG_ROOT_PASSWORD_HASHED    },
1314
                { "root-shell",              required_argument, NULL, ARG_ROOT_SHELL              },
1315
                { "kernel-command-line",     required_argument, NULL, ARG_KERNEL_COMMAND_LINE     },
1316
                { "prompt",                  no_argument,       NULL, ARG_PROMPT                  },
1317
                { "prompt-locale",           no_argument,       NULL, ARG_PROMPT_LOCALE           },
1318
                { "prompt-keymap",           no_argument,       NULL, ARG_PROMPT_KEYMAP           },
1319
                { "prompt-timezone",         no_argument,       NULL, ARG_PROMPT_TIMEZONE         },
1320
                { "prompt-hostname",         no_argument,       NULL, ARG_PROMPT_HOSTNAME         },
1321
                { "prompt-root-password",    no_argument,       NULL, ARG_PROMPT_ROOT_PASSWORD    },
1322
                { "prompt-root-shell",       no_argument,       NULL, ARG_PROMPT_ROOT_SHELL       },
1323
                { "copy",                    no_argument,       NULL, ARG_COPY                    },
1324
                { "copy-locale",             no_argument,       NULL, ARG_COPY_LOCALE             },
1325
                { "copy-keymap",             no_argument,       NULL, ARG_COPY_KEYMAP             },
1326
                { "copy-timezone",           no_argument,       NULL, ARG_COPY_TIMEZONE           },
1327
                { "copy-root-password",      no_argument,       NULL, ARG_COPY_ROOT_PASSWORD      },
1328
                { "copy-root-shell",         no_argument,       NULL, ARG_COPY_ROOT_SHELL         },
1329
                { "force",                   no_argument,       NULL, ARG_FORCE                   },
1330
                { "delete-root-password",    no_argument,       NULL, ARG_DELETE_ROOT_PASSWORD    },
1331
                { "welcome",                 required_argument, NULL, ARG_WELCOME                 },
1332
                { "chrome",                  required_argument, NULL, ARG_CHROME                  },
1333
                { "reset",                   no_argument,       NULL, ARG_RESET                   },
1334
                {}
1335
        };
1336

1337
        int r, c;
141✔
1338

1339
        assert(argc >= 0);
141✔
1340
        assert(argv);
141✔
1341

1342
        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
665✔
1343

1344
                switch (c) {
526✔
1345

UNCOV
1346
                case 'h':
×
UNCOV
1347
                        return help();
×
1348

UNCOV
1349
                case ARG_VERSION:
×
UNCOV
1350
                        return version();
×
1351

1352
                case ARG_ROOT:
37✔
1353
                        r = parse_path_argument(optarg, true, &arg_root);
37✔
1354
                        if (r < 0)
37✔
1355
                                return r;
1356
                        break;
1357

UNCOV
1358
                case ARG_IMAGE:
×
UNCOV
1359
                        r = parse_path_argument(optarg, false, &arg_image);
×
UNCOV
1360
                        if (r < 0)
×
1361
                                return r;
1362
                        break;
1363

UNCOV
1364
                case ARG_IMAGE_POLICY:
×
UNCOV
1365
                        r = parse_image_policy_argument(optarg, &arg_image_policy);
×
UNCOV
1366
                        if (r < 0)
×
1367
                                return r;
1368
                        break;
1369

1370
                case ARG_LOCALE:
5✔
1371
                        r = free_and_strdup(&arg_locale, optarg);
5✔
1372
                        if (r < 0)
5✔
UNCOV
1373
                                return log_oom();
×
1374

1375
                        break;
1376

1377
                case ARG_LOCALE_MESSAGES:
4✔
1378
                        r = free_and_strdup(&arg_locale_messages, optarg);
4✔
1379
                        if (r < 0)
4✔
UNCOV
1380
                                return log_oom();
×
1381

1382
                        break;
1383

1384
                case ARG_KEYMAP:
4✔
1385
                        if (!keymap_is_valid(optarg))
4✔
1386
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1387
                                                       "Keymap %s is not valid.", optarg);
1388

1389
                        r = free_and_strdup(&arg_keymap, optarg);
4✔
1390
                        if (r < 0)
4✔
UNCOV
1391
                                return log_oom();
×
1392

1393
                        break;
1394

1395
                case ARG_TIMEZONE:
5✔
1396
                        if (!timezone_is_valid(optarg, LOG_ERR))
5✔
1397
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1✔
1398
                                                       "Timezone %s is not valid.", optarg);
1399

1400
                        r = free_and_strdup(&arg_timezone, optarg);
4✔
1401
                        if (r < 0)
4✔
UNCOV
1402
                                return log_oom();
×
1403

1404
                        break;
1405

1406
                case ARG_ROOT_PASSWORD:
4✔
1407
                        r = free_and_strdup(&arg_root_password, optarg);
4✔
1408
                        if (r < 0)
4✔
UNCOV
1409
                                return log_oom();
×
1410

1411
                        arg_root_password_is_hashed = false;
4✔
1412
                        break;
4✔
1413

1414
                case ARG_ROOT_PASSWORD_FILE:
1✔
1415
                        arg_root_password = mfree(arg_root_password);
1✔
1416

1417
                        r = read_one_line_file(optarg, &arg_root_password);
1✔
1418
                        if (r < 0)
1✔
UNCOV
1419
                                return log_error_errno(r, "Failed to read %s: %m", optarg);
×
1420

1421
                        arg_root_password_is_hashed = false;
1✔
1422
                        break;
1✔
1423

1424
                case ARG_ROOT_PASSWORD_HASHED:
4✔
1425
                        r = free_and_strdup(&arg_root_password, optarg);
4✔
1426
                        if (r < 0)
4✔
UNCOV
1427
                                return log_oom();
×
1428

1429
                        arg_root_password_is_hashed = true;
4✔
1430
                        break;
4✔
1431

1432
                case ARG_ROOT_SHELL:
5✔
1433
                        r = free_and_strdup(&arg_root_shell, optarg);
5✔
1434
                        if (r < 0)
5✔
UNCOV
1435
                                return log_oom();
×
1436

1437
                        break;
1438

1439
                case ARG_HOSTNAME:
5✔
1440
                        if (!hostname_is_valid(optarg, VALID_HOSTNAME_TRAILING_DOT|VALID_HOSTNAME_QUESTION_MARK))
5✔
UNCOV
1441
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1442
                                                       "Host name %s is not valid.", optarg);
1443

1444
                        r = free_and_strdup(&arg_hostname, optarg);
5✔
1445
                        if (r < 0)
5✔
UNCOV
1446
                                return log_oom();
×
1447

1448
                        hostname_cleanup(arg_hostname);
5✔
1449
                        break;
5✔
1450

1451
                case ARG_SETUP_MACHINE_ID:
1✔
1452
                        r = sd_id128_randomize(&arg_machine_id);
1✔
1453
                        if (r < 0)
1✔
UNCOV
1454
                                return log_error_errno(r, "Failed to generate randomized machine ID: %m");
×
1455

1456
                        break;
1457

1458
                case ARG_MACHINE_ID:
4✔
1459
                        r = sd_id128_from_string(optarg, &arg_machine_id);
4✔
1460
                        if (r < 0)
4✔
1461
                                return log_error_errno(r, "Failed to parse machine id %s.", optarg);
1✔
1462

1463
                        break;
1464

1465
                case ARG_KERNEL_COMMAND_LINE:
3✔
1466
                        r = free_and_strdup(&arg_kernel_cmdline, optarg);
3✔
1467
                        if (r < 0)
3✔
UNCOV
1468
                                return log_oom();
×
1469

1470
                        break;
1471

UNCOV
1472
                case ARG_PROMPT:
×
UNCOV
1473
                        arg_prompt_locale = arg_prompt_keymap = arg_prompt_timezone = arg_prompt_hostname =
×
UNCOV
1474
                                arg_prompt_root_password = arg_prompt_root_shell = true;
×
1475
                        break;
×
1476

1477
                case ARG_PROMPT_LOCALE:
106✔
1478
                        arg_prompt_locale = true;
106✔
1479
                        break;
106✔
1480

1481
                case ARG_PROMPT_KEYMAP:
106✔
1482
                        arg_prompt_keymap = true;
106✔
1483
                        break;
106✔
1484

1485
                case ARG_PROMPT_TIMEZONE:
106✔
1486
                        arg_prompt_timezone = true;
106✔
1487
                        break;
106✔
1488

1489
                case ARG_PROMPT_HOSTNAME:
1✔
1490
                        arg_prompt_hostname = true;
1✔
1491
                        break;
1✔
1492

1493
                case ARG_PROMPT_ROOT_PASSWORD:
106✔
1494
                        arg_prompt_root_password = true;
106✔
1495
                        break;
106✔
1496

1497
                case ARG_PROMPT_ROOT_SHELL:
4✔
1498
                        arg_prompt_root_shell = true;
4✔
1499
                        break;
4✔
1500

1501
                case ARG_COPY:
1✔
1502
                        arg_copy_locale = arg_copy_keymap = arg_copy_timezone = arg_copy_root_password =
1✔
1503
                                arg_copy_root_shell = true;
1✔
1504
                        break;
1✔
1505

1506
                case ARG_COPY_LOCALE:
2✔
1507
                        arg_copy_locale = true;
2✔
1508
                        break;
2✔
1509

1510
                case ARG_COPY_KEYMAP:
2✔
1511
                        arg_copy_keymap = true;
2✔
1512
                        break;
2✔
1513

1514
                case ARG_COPY_TIMEZONE:
2✔
1515
                        arg_copy_timezone = true;
2✔
1516
                        break;
2✔
1517

1518
                case ARG_COPY_ROOT_PASSWORD:
1✔
1519
                        arg_copy_root_password = true;
1✔
1520
                        break;
1✔
1521

1522
                case ARG_COPY_ROOT_SHELL:
1✔
1523
                        arg_copy_root_shell = true;
1✔
1524
                        break;
1✔
1525

1526
                case ARG_FORCE:
3✔
1527
                        arg_force = true;
3✔
1528
                        break;
3✔
1529

1530
                case ARG_DELETE_ROOT_PASSWORD:
1✔
1531
                        arg_delete_root_password = true;
1✔
1532
                        break;
1✔
1533

1534
                case ARG_WELCOME:
1✔
1535
                        r = parse_boolean(optarg);
1✔
1536
                        if (r < 0)
1✔
UNCOV
1537
                                return log_error_errno(r, "Failed to parse --welcome= argument: %s", optarg);
×
1538

1539
                        arg_welcome = r;
1✔
1540
                        break;
1✔
1541

UNCOV
1542
                case ARG_CHROME:
×
UNCOV
1543
                        r = parse_boolean_argument("--chrome=", optarg, &arg_chrome);
×
UNCOV
1544
                        if (r < 0)
×
1545
                                return r;
1546

1547
                        break;
1548

1549
                case ARG_RESET:
1✔
1550
                        arg_reset = true;
1✔
1551
                        break;
1✔
1552

1553
                case '?':
1554
                        return -EINVAL;
1555

UNCOV
1556
                default:
×
UNCOV
1557
                        assert_not_reached();
×
1558
                }
1559

1560
        if (arg_delete_root_password && (arg_copy_root_password || arg_root_password || arg_prompt_root_password))
139✔
UNCOV
1561
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1562
                                       "--delete-root-password cannot be combined with other root password options.");
1563

1564
        if (arg_image && arg_root)
139✔
UNCOV
1565
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1566
                                       "--root= and --image= cannot be used together.");
1567

1568
        if (!sd_id128_is_null(arg_machine_id) && !(arg_image || arg_root) && !arg_force)
274✔
UNCOV
1569
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1570
                                       "--machine-id=/--setup-machine-id only works with --root= or --image=.");
1571

1572
        return 1;
1573
}
1574

UNCOV
1575
static int reload_system_manager(sd_bus **bus) {
×
UNCOV
1576
        int r;
×
1577

UNCOV
1578
        assert(bus);
×
1579

UNCOV
1580
        if (!*bus) {
×
UNCOV
1581
                r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, RUNTIME_SCOPE_SYSTEM, bus);
×
UNCOV
1582
                if (r < 0)
×
UNCOV
1583
                        return bus_log_connect_error(r, BUS_TRANSPORT_LOCAL, RUNTIME_SCOPE_SYSTEM);
×
1584
        }
1585

UNCOV
1586
        r = bus_service_manager_reload(*bus);
×
UNCOV
1587
        if (r < 0)
×
1588
                return r;
1589

1590
        log_info("Requested manager reload to apply locale configuration.");
×
1591
        return 0;
1592
}
1593

1594
static int reload_vconsole(sd_bus **bus) {
×
UNCOV
1595
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
UNCOV
1596
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
×
UNCOV
1597
        _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
×
1598
        const char *object;
×
UNCOV
1599
        int r;
×
1600

UNCOV
1601
        assert(bus);
×
1602

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

1609
        r = bus_wait_for_jobs_new(*bus, &w);
×
UNCOV
1610
        if (r < 0)
×
1611
                return log_error_errno(r, "Could not watch jobs: %m");
×
1612

1613
        r = bus_call_method(*bus, bus_systemd_mgr, "RestartUnit", &error, &reply,
×
1614
                            "ss", "systemd-vconsole-setup.service", "replace");
1615
        if (r < 0)
×
1616
                return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
×
1617

UNCOV
1618
        r = sd_bus_message_read(reply, "o", &object);
×
1619
        if (r < 0)
×
1620
                return bus_log_parse_error(r);
×
1621

UNCOV
1622
        r = bus_wait_for_jobs_one(w, object, BUS_WAIT_JOBS_LOG_ERROR, NULL);
×
1623
        if (r < 0)
×
UNCOV
1624
                return log_error_errno(r, "Failed to wait for systemd-vconsole-setup.service/restart: %m");
×
1625
        return 0;
1626
}
1627

1628
static int run(int argc, char *argv[]) {
141✔
1629
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
141✔
1630
        _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
141✔
1631
        _cleanup_(umount_and_freep) char *mounted_dir = NULL;
×
1632
        _cleanup_close_ int rfd = -EBADF;
141✔
1633
        int r;
141✔
1634

1635
        r = parse_argv(argc, argv);
141✔
1636
        if (r <= 0)
141✔
1637
                return r;
1638

1639
        log_setup();
139✔
1640

1641
        umask(0022);
139✔
1642

1643
        bool offline = arg_root || arg_image;
139✔
1644

1645
        if (!offline) {
104✔
1646
                /* If we are called without --root=/--image= let's honour the systemd.firstboot kernel
1647
                 * command line option, because we are called to provision the host with basic settings (as
1648
                 * opposed to some other file system tree/image) */
1649

1650
                bool enabled;
104✔
1651
                r = proc_cmdline_get_bool("systemd.firstboot", /* flags = */ 0, &enabled);
104✔
1652
                if (r < 0)
104✔
1653
                        return log_error_errno(r, "Failed to parse systemd.firstboot= kernel command line argument, ignoring: %m");
×
1654
                if (r > 0 && !enabled) {
104✔
1655
                        log_debug("Found systemd.firstboot=no kernel command line argument, turning off all prompts.");
104✔
1656
                        arg_prompt_locale = arg_prompt_keymap = arg_prompt_timezone = arg_prompt_hostname = arg_prompt_root_password = arg_prompt_root_shell = false;
104✔
1657
                }
1658
        }
1659

1660
        r = mac_init();
139✔
1661
        if (r < 0)
139✔
1662
                return r;
1663

1664
        if (arg_image) {
139✔
UNCOV
1665
                assert(!arg_root);
×
1666

UNCOV
1667
                r = mount_image_privately_interactively(
×
1668
                                arg_image,
1669
                                arg_image_policy,
1670
                                DISSECT_IMAGE_GENERIC_ROOT |
1671
                                DISSECT_IMAGE_REQUIRE_ROOT |
1672
                                DISSECT_IMAGE_VALIDATE_OS |
1673
                                DISSECT_IMAGE_RELAX_VAR_CHECK |
1674
                                DISSECT_IMAGE_FSCK |
1675
                                DISSECT_IMAGE_GROWFS |
1676
                                DISSECT_IMAGE_ALLOW_USERSPACE_VERITY,
1677
                                &mounted_dir,
1678
                                &rfd,
1679
                                &loop_device);
UNCOV
1680
                if (r < 0)
×
1681
                        return r;
1682

UNCOV
1683
                arg_root = strdup(mounted_dir);
×
UNCOV
1684
                if (!arg_root)
×
UNCOV
1685
                        return log_oom();
×
1686
        } else {
1687
                rfd = open(empty_to_root(arg_root), O_DIRECTORY|O_CLOEXEC);
139✔
1688
                if (rfd < 0)
139✔
UNCOV
1689
                        return log_error_errno(errno, "Failed to open %s: %m", empty_to_root(arg_root));
×
1690
        }
1691

1692
        LOG_SET_PREFIX(arg_image ?: arg_root);
280✔
1693
        DEFER_VOID_CALL(chrome_hide);
139✔
1694

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

1698
        if (arg_keymap && !keymap_is_ok(arg_keymap, FD_TO_PTR(rfd)))
139✔
UNCOV
1699
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Keymap %s is not installed.", arg_keymap);
×
1700
        if (arg_locale && !locale_is_ok(arg_locale, FD_TO_PTR(rfd)))
139✔
UNCOV
1701
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale);
×
1702
        if (arg_locale_messages && !locale_is_ok(arg_locale_messages, FD_TO_PTR(rfd)))
139✔
UNCOV
1703
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale_messages);
×
1704

1705
        if (arg_root_shell) {
139✔
1706
                r = find_shell(rfd, arg_root_shell);
5✔
1707
                if (r < 0)
5✔
1708
                        return r;
1709
        }
1710

1711
        r = process_reset(rfd);
138✔
1712
        if (r < 0)
138✔
1713
                return r;
1714

1715
        r = process_locale(rfd);
138✔
1716
        if (r < 0)
138✔
1717
                return r;
1718
        if (r > 0 && !offline)
138✔
UNCOV
1719
                (void) reload_system_manager(&bus);
×
1720

1721
        r = process_keymap(rfd);
138✔
1722
        if (r < 0)
138✔
1723
                return r;
1724
        if (r > 0 && !offline)
138✔
UNCOV
1725
                (void) reload_vconsole(&bus);
×
1726

1727
        r = process_timezone(rfd);
138✔
1728
        if (r < 0)
138✔
1729
                return r;
1730

1731
        r = process_hostname(rfd);
138✔
1732
        if (r < 0)
138✔
1733
                return r;
1734

1735
        r = process_root_account(rfd);
138✔
1736
        if (r < 0)
138✔
1737
                return r;
1738

1739
        r = process_kernel_cmdline(rfd);
138✔
1740
        if (r < 0)
138✔
1741
                return r;
1742

1743
        r = process_machine_id(rfd);
138✔
1744
        if (r < 0)
138✔
UNCOV
1745
                return r;
×
1746

1747
        return 0;
1748
}
1749

1750
DEFINE_MAIN_FUNCTION(run);
141✔
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