]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/firstboot/firstboot.c
man: systemd-measure. Remove 'tpm2-pcrs=' from cryptenroll command (#39590)
[thirdparty/systemd.git] / src / firstboot / firstboot.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
418b9be5 2
418b9be5 3#include <fcntl.h>
418b9be5 4#include <getopt.h>
3f6fd1ba 5#include <unistd.h>
418b9be5 6
8857aa74 7#include "sd-bus.h"
dccca82b 8#include "sd-id128.h"
0d2cc656 9#include "sd-varlink.h"
dccca82b 10
b5efdb8a 11#include "alloc-util.h"
3f6fd1ba 12#include "ask-password-api.h"
d6b4d1c7 13#include "build.h"
cea32691
ZJS
14#include "bus-error.h"
15#include "bus-locator.h"
a9399358 16#include "bus-unit-util.h"
cea32691 17#include "bus-util.h"
8eb668b9 18#include "bus-wait-for-jobs.h"
f461a28d 19#include "chase.h"
418b9be5 20#include "copy.h"
416f7b3a 21#include "creds-util.h"
3ff9fa59 22#include "dissect-image.h"
686d13b9 23#include "env-file.h"
7fc3f9c0 24#include "errno-util.h"
6bedfcbb 25#include "fd-util.h"
3f6fd1ba 26#include "fileio.h"
f4f15635 27#include "fs-util.h"
d8e32c47 28#include "glyph-util.h"
3f6fd1ba 29#include "hostname-util.h"
8aa304d3 30#include "image-policy.h"
f05e1d0d 31#include "kbd-util.h"
9ea5a6e7 32#include "label.h"
611bb28d 33#include "label-util.h"
42f3b2f9 34#include "libcrypt-util.h"
0dc39dff 35#include "locale-setup.h"
3f6fd1ba 36#include "locale-util.h"
b352e545 37#include "lock-util.h"
8857aa74 38#include "loop-util.h"
45f39418 39#include "main-func.h"
9ae4ef49 40#include "memory-util.h"
3ff9fa59 41#include "mount-util.h"
d58ad743 42#include "os-util.h"
614b022c 43#include "parse-argument.h"
6bedfcbb 44#include "parse-util.h"
d34b1823 45#include "password-quality-util.h"
418b9be5 46#include "path-util.h"
294bf0c3 47#include "pretty-print.h"
f582cbca 48#include "proc-cmdline.h"
fa350969 49#include "prompt-util.h"
8857aa74 50#include "runtime-scope.h"
ce0458be 51#include "smack-util.h"
8857aa74 52#include "stat-util.h"
6bedfcbb 53#include "string-util.h"
3f6fd1ba 54#include "strv.h"
288a74cc 55#include "terminal-util.h"
3f6fd1ba 56#include "time-util.h"
b4909a3f 57#include "tmpfile-util-label.h"
e929bee0 58#include "user-util.h"
8a008fa7 59#include "vconsole-util.h"
418b9be5
LP
60
61static char *arg_root = NULL;
3ff9fa59 62static char *arg_image = NULL;
418b9be5
LP
63static char *arg_locale = NULL; /* $LANG */
64static char *arg_locale_messages = NULL; /* $LC_MESSAGES */
f8fd0930 65static char *arg_keymap = NULL;
418b9be5
LP
66static char *arg_timezone = NULL;
67static char *arg_hostname = NULL;
68static sd_id128_t arg_machine_id = {};
69static char *arg_root_password = NULL;
28900a1b 70static char *arg_root_shell = NULL;
a5925354 71static char *arg_kernel_cmdline = NULL;
418b9be5 72static bool arg_prompt_locale = false;
ed457f13 73static bool arg_prompt_keymap = false;
aa27bec1 74static bool arg_prompt_keymap_auto = false;
418b9be5
LP
75static bool arg_prompt_timezone = false;
76static bool arg_prompt_hostname = false;
77static bool arg_prompt_root_password = false;
28900a1b 78static bool arg_prompt_root_shell = false;
418b9be5 79static bool arg_copy_locale = false;
ed457f13 80static bool arg_copy_keymap = false;
418b9be5
LP
81static bool arg_copy_timezone = false;
82static bool arg_copy_root_password = false;
28900a1b 83static bool arg_copy_root_shell = false;
b4909a3f 84static bool arg_force = false;
4926ceaf 85static bool arg_delete_root_password = false;
676339a1 86static bool arg_root_password_is_hashed = false;
a1225020 87static bool arg_welcome = true;
05eb2c60 88static bool arg_reset = false;
84be0c71 89static ImagePolicy *arg_image_policy = NULL;
73ee723a 90static bool arg_chrome = true;
0d2cc656 91static bool arg_mute_console = false;
418b9be5 92
45f39418 93STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
3ff9fa59 94STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
45f39418
YW
95STATIC_DESTRUCTOR_REGISTER(arg_locale, freep);
96STATIC_DESTRUCTOR_REGISTER(arg_locale_messages, freep);
97STATIC_DESTRUCTOR_REGISTER(arg_keymap, freep);
98STATIC_DESTRUCTOR_REGISTER(arg_timezone, freep);
99STATIC_DESTRUCTOR_REGISTER(arg_hostname, freep);
9ae4ef49 100STATIC_DESTRUCTOR_REGISTER(arg_root_password, erase_and_freep);
4f464e74
AAF
101STATIC_DESTRUCTOR_REGISTER(arg_root_shell, freep);
102STATIC_DESTRUCTOR_REGISTER(arg_kernel_cmdline, freep);
84be0c71 103STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
45f39418 104
0d2cc656 105static void print_welcome(int rfd, sd_varlink **mute_console_link) {
02b7005e 106 _cleanup_free_ char *pretty_name = NULL, *os_name = NULL, *ansi_color = NULL;
418b9be5 107 static bool done = false;
ae0d36c1 108 const char *pn, *ac;
418b9be5
LP
109 int r;
110
a0657479 111 assert(rfd >= 0);
0d2cc656
LP
112 assert(mute_console_link);
113
114 if (!*mute_console_link && arg_mute_console)
115 (void) mute_console(mute_console_link);
a0657479 116
a1225020
LP
117 if (!arg_welcome)
118 return;
119
f4da5ed5
MF
120 if (done) {
121 putchar('\n'); /* Add some breathing room between multiple prompts */
418b9be5 122 return;
f4da5ed5 123 }
418b9be5 124
73ee723a
LP
125 (void) terminal_reset_defensive_locked(STDOUT_FILENO, /* flags= */ 0);
126
127 if (arg_chrome)
128 chrome_show("Initial Setup", /* bottom= */ NULL);
129
a0657479
DDM
130 r = parse_os_release_at(rfd,
131 "PRETTY_NAME", &pretty_name,
132 "NAME", &os_name,
133 "ANSI_COLOR", &ansi_color);
d58ad743
LP
134 if (r < 0)
135 log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
136 "Failed to read os-release file, ignoring: %m");
418b9be5 137
02b7005e 138 pn = os_release_pretty_name(pretty_name, os_name);
ae0d36c1 139 ac = isempty(ansi_color) ? "0" : ansi_color;
4aeadec7
LP
140
141 if (colors_enabled())
372f3159 142 printf(ANSI_HIGHLIGHT "Welcome to " ANSI_NORMAL "\x1B[%sm%s" ANSI_HIGHLIGHT "!" ANSI_NORMAL "\n", ac, pn);
4aeadec7 143 else
372f3159 144 printf("Welcome to %s!\n", pn);
4aeadec7 145
d810815e
LP
146 putchar('\n');
147 if (emoji_enabled()) {
1ae9b0cf 148 fputs(glyph(GLYPH_SPARKLES), stdout);
d810815e
LP
149 putchar(' ');
150 }
372f3159 151 printf("Please configure the system!\n\n");
418b9be5
LP
152
153 done = true;
154}
155
b352e545 156static int should_configure(int dir_fd, const char *filename) {
a777a592
ZJS
157 _cleanup_fclose_ FILE *passwd = NULL, *shadow = NULL;
158 int r;
159
b352e545
DDM
160 assert(dir_fd >= 0);
161 assert(filename);
162
a777a592
ZJS
163 if (streq(filename, "passwd") && !arg_force)
164 /* We may need to do additional checks, so open the file. */
165 r = xfopenat(dir_fd, filename, "re", O_NOFOLLOW, &passwd);
166 else
167 r = RET_NERRNO(faccessat(dir_fd, filename, F_OK, AT_SYMLINK_NOFOLLOW));
168
169 if (r == -ENOENT)
170 return true; /* missing */
171 if (r < 0)
172 return log_error_errno(r, "Failed to access %s: %m", filename);
173 if (arg_force)
174 return true; /* exists, but if --force was given we should still configure the file. */
175
176 if (!passwd)
177 return false;
178
179 /* In case of /etc/passwd, do an additional check for the root password field.
180 * We first check that passwd redirects to shadow, and then we check shadow.
181 */
182 struct passwd *i;
183 while ((r = fgetpwent_sane(passwd, &i)) > 0) {
184 if (!streq(i->pw_name, "root"))
185 continue;
186
187 if (streq_ptr(i->pw_passwd, PASSWORD_SEE_SHADOW))
188 break;
189 log_debug("passwd: root account with non-shadow password found, treating root as configured");
190 return false;
191 }
192 if (r < 0)
193 return log_error_errno(r, "Failed to read %s: %m", filename);
194 if (r == 0) {
195 log_debug("No root account found in %s, assuming root is not configured.", filename);
196 return true;
197 }
df00c516 198
a777a592
ZJS
199 r = xfopenat(dir_fd, "shadow", "re", O_NOFOLLOW, &shadow);
200 if (r == -ENOENT) {
201 log_debug("No shadow file found, assuming root is not configured.");
df00c516
DDM
202 return true; /* missing */
203 }
a777a592
ZJS
204 if (r < 0)
205 return log_error_errno(r, "Failed to access shadow: %m");
b352e545 206
a777a592
ZJS
207 struct spwd *j;
208 while ((r = fgetspent_sane(shadow, &j)) > 0) {
209 if (!streq(j->sp_namp, "root"))
210 continue;
211
212 bool unprovisioned = streq_ptr(j->sp_pwdp, PASSWORD_UNPROVISIONED);
213 log_debug("Root account found, %s.",
214 unprovisioned ? "with unprovisioned password, treating root as not configured" :
215 "treating root as configured");
216 return unprovisioned;
217 }
218 if (r < 0)
219 return log_error_errno(r, "Failed to read shadow: %m");
220 assert(r == 0);
221 log_debug("No root account found in shadow, assuming root is not configured.");
222 return true;
b352e545
DDM
223}
224
fa350969
LP
225static int locale_is_ok(const char *name, void *userdata) {
226 int rfd = ASSERT_FD(PTR_TO_FD(userdata)), r;
a00a78b8 227
178d80d7
MF
228 r = dir_fd_is_root(rfd);
229 if (r < 0)
230 log_debug_errno(r, "Unable to determine if operating on host root directory, assuming we are: %m");
231
fa350969 232 return r != 0 ? locale_is_installed(name) > 0 : locale_is_valid(name);
a00a78b8
LP
233}
234
0d2cc656 235static int prompt_locale(int rfd, sd_varlink **mute_console_link) {
418b9be5 236 _cleanup_strv_free_ char **locales = NULL;
416f7b3a 237 bool acquired_from_creds = false;
418b9be5
LP
238 int r;
239
a0657479
DDM
240 assert(rfd >= 0);
241
418b9be5
LP
242 if (arg_locale || arg_locale_messages)
243 return 0;
244
416f7b3a
LP
245 r = read_credential("firstboot.locale", (void**) &arg_locale, NULL);
246 if (r < 0)
247 log_debug_errno(r, "Failed to read credential firstboot.locale, ignoring: %m");
248 else
249 acquired_from_creds = true;
250
251 r = read_credential("firstboot.locale-messages", (void**) &arg_locale_messages, NULL);
252 if (r < 0)
8914f7e8 253 log_debug_errno(r, "Failed to read credential firstboot.locale-messages, ignoring: %m");
416f7b3a
LP
254 else
255 acquired_from_creds = true;
256
257 if (acquired_from_creds) {
258 log_debug("Acquired locale from credentials.");
259 return 0;
260 }
261
eb650ffe
ZJS
262 if (!arg_prompt_locale) {
263 log_debug("Prompting for locale was not requested.");
418b9be5 264 return 0;
eb650ffe 265 }
418b9be5
LP
266
267 r = get_locales(&locales);
23bbb0de
MS
268 if (r < 0)
269 return log_error_errno(r, "Cannot query locales list: %m");
418b9be5 270
bdd7cd26
LP
271 if (strv_isempty(locales))
272 log_debug("No locales found, skipping locale selection.");
273 else if (strv_length(locales) == 1) {
418b9be5 274
bdd7cd26
LP
275 if (streq(locales[0], SYSTEMD_DEFAULT_LOCALE))
276 log_debug("Only installed locale is default locale anyway, not setting locale explicitly.");
277 else {
278 log_debug("Only a single locale available (%s), selecting it as default.", locales[0]);
418b9be5 279
bdd7cd26
LP
280 arg_locale = strdup(locales[0]);
281 if (!arg_locale)
282 return log_oom();
418b9be5 283
bdd7cd26
LP
284 /* Not setting arg_locale_message here, since it defaults to LANG anyway */
285 }
286 } else {
0d2cc656 287 print_welcome(rfd, mute_console_link);
418b9be5 288
fa350969
LP
289 r = prompt_loop("Please enter the new system locale name or number",
290 GLYPH_WORLD,
291 locales,
292 /* accepted= */ NULL,
293 /* ellipsize_percentage= */ 60,
294 /* n_columns= */ 3,
295 /* column_width= */ 20,
296 locale_is_ok,
297 /* refresh= */ NULL,
298 FD_TO_PTR(rfd),
299 PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
300 &arg_locale);
bdd7cd26
LP
301 if (r < 0)
302 return r;
bdd7cd26
LP
303 if (isempty(arg_locale))
304 return 0;
305
fa350969
LP
306 r = prompt_loop("Please enter the new system message locale name or number",
307 GLYPH_WORLD,
308 locales,
309 /* accepted= */ NULL,
310 /* ellipsize_percentage= */ 60,
311 /* n_columns= */ 3,
312 /* column_width= */ 20,
313 locale_is_ok,
314 /* refresh= */ NULL,
315 FD_TO_PTR(rfd),
316 PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
317 &arg_locale_messages);
bdd7cd26
LP
318 if (r < 0)
319 return r;
320
321 /* Suppress the messages setting if it's the same as the main locale anyway */
322 if (streq_ptr(arg_locale, arg_locale_messages))
323 arg_locale_messages = mfree(arg_locale_messages);
324 }
418b9be5
LP
325
326 return 0;
327}
328
0d2cc656 329static int process_locale(int rfd, sd_varlink **mute_console_link) {
b352e545
DDM
330 _cleanup_close_ int pfd = -EBADF;
331 _cleanup_free_ char *f = NULL;
418b9be5
LP
332 char* locales[3];
333 unsigned i = 0;
334 int r;
335
b352e545
DDM
336 assert(rfd >= 0);
337
0dc39dff 338 pfd = chase_and_open_parent_at(rfd, etc_locale_conf(),
b39710cc 339 CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
b352e545
DDM
340 &f);
341 if (pfd < 0)
342 return log_error_errno(pfd, "Failed to chase /etc/locale.conf: %m");
418b9be5 343
b352e545
DDM
344 r = should_configure(pfd, f);
345 if (r == 0)
346 log_debug("Found /etc/locale.conf, assuming locale information has been configured.");
347 if (r <= 0)
348 return r;
418b9be5 349
fe75d5bc
DDM
350 r = dir_fd_is_root(rfd);
351 if (r < 0)
352 return log_error_errno(r, "Failed to check if directory file descriptor is root: %m");
353
354 if (arg_copy_locale && r == 0) {
0dc39dff 355 r = copy_file_atomic_at(AT_FDCWD, etc_locale_conf(), pfd, f, 0644, COPY_REFLINK);
418b9be5 356 if (r != -ENOENT) {
23bbb0de 357 if (r < 0)
b352e545 358 return log_error_errno(r, "Failed to copy host's /etc/locale.conf: %m");
418b9be5 359
b352e545 360 log_info("Copied host's /etc/locale.conf.");
418b9be5
LP
361 return 0;
362 }
363 }
364
0d2cc656 365 r = prompt_locale(rfd, mute_console_link);
418b9be5
LP
366 if (r < 0)
367 return r;
368
369 if (!isempty(arg_locale))
63c372cb 370 locales[i++] = strjoina("LANG=", arg_locale);
4c4a73ce 371 if (!isempty(arg_locale_messages) && !streq_ptr(arg_locale_messages, arg_locale))
63c372cb 372 locales[i++] = strjoina("LC_MESSAGES=", arg_locale_messages);
418b9be5
LP
373
374 if (i == 0)
375 return 0;
376
377 locales[i] = NULL;
378
3e5320e2
LP
379 r = write_env_file(
380 pfd,
381 f,
382 /* headers= */ NULL,
383 locales,
384 WRITE_ENV_FILE_LABEL);
23bbb0de 385 if (r < 0)
b352e545 386 return log_error_errno(r, "Failed to write /etc/locale.conf: %m");
418b9be5 387
b352e545 388 log_info("/etc/locale.conf written.");
d0c50d8d 389 return 1;
418b9be5
LP
390}
391
fa350969
LP
392static int keymap_is_ok(const char* name, void *userdata) {
393 int rfd = ASSERT_FD(PTR_TO_FD(userdata)), r;
178d80d7 394
321a8c59
ED
395 r = dir_fd_is_root(rfd);
396 if (r < 0)
397 log_debug_errno(r, "Unable to determine if operating on host root directory, assuming we are: %m");
398
fa350969 399 return r != 0 ? keymap_exists(name) > 0 : keymap_is_valid(name);
321a8c59
ED
400}
401
0d2cc656 402static int prompt_keymap(int rfd, sd_varlink **mute_console_link) {
ed457f13
TB
403 _cleanup_strv_free_ char **kmaps = NULL;
404 int r;
405
a0657479
DDM
406 assert(rfd >= 0);
407
ed457f13
TB
408 if (arg_keymap)
409 return 0;
410
416f7b3a
LP
411 r = read_credential("firstboot.keymap", (void**) &arg_keymap, NULL);
412 if (r < 0)
413 log_debug_errno(r, "Failed to read credential firstboot.keymap, ignoring: %m");
414 else {
415 log_debug("Acquired keymap from credential.");
416 return 0;
417 }
418
aa27bec1
LP
419 bool b;
420 if (arg_prompt_keymap_auto) {
421 _cleanup_free_ char *ttyname = NULL;
422
423 r = getttyname_harder(STDOUT_FILENO, &ttyname);
424 if (r < 0) {
425 log_debug_errno(r, "Cannot determine TTY we are connected, ignoring: %m");
426 b = false; /* if we can't resolve this, it's probably not a VT */
427 } else {
428 b = tty_is_vc_resolve(ttyname);
429 log_debug("Detected connection to local console: %s", yes_no(b));
430 }
431 } else
432 b = arg_prompt_keymap;
433 if (!b) {
eb650ffe 434 log_debug("Prompting for keymap was not requested.");
ed457f13 435 return 0;
eb650ffe 436 }
ed457f13
TB
437
438 r = get_keymaps(&kmaps);
439 if (r == -ENOENT) /* no keymaps installed */
eb650ffe 440 return log_debug_errno(r, "No keymaps are installed.");
ed457f13
TB
441 if (r < 0)
442 return log_error_errno(r, "Failed to read keymaps: %m");
443
0d2cc656 444 print_welcome(rfd, mute_console_link);
ed457f13 445
fa350969
LP
446 return prompt_loop(
447 "Please enter the new keymap name or number",
448 GLYPH_KEYBOARD,
449 kmaps,
450 /* accepted= */ NULL,
451 /* ellipsize_percentage= */ 60,
452 /* n_columns= */ 3,
453 /* column_width= */ 20,
454 keymap_is_ok,
455 /* refresh= */ NULL,
456 FD_TO_PTR(rfd),
457 PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
458 &arg_keymap);
ed457f13
TB
459}
460
0d2cc656 461static int process_keymap(int rfd, sd_varlink **mute_console_link) {
b352e545
DDM
462 _cleanup_close_ int pfd = -EBADF;
463 _cleanup_free_ char *f = NULL;
8a008fa7 464 _cleanup_strv_free_ char **keymap = NULL;
ed457f13
TB
465 int r;
466
b352e545 467 assert(rfd >= 0);
ed457f13 468
0dc39dff 469 pfd = chase_and_open_parent_at(rfd, etc_vconsole_conf(),
b39710cc 470 CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
b352e545
DDM
471 &f);
472 if (pfd < 0)
473 return log_error_errno(pfd, "Failed to chase /etc/vconsole.conf: %m");
ed457f13 474
b352e545
DDM
475 r = should_configure(pfd, f);
476 if (r == 0)
477 log_debug("Found /etc/vconsole.conf, assuming console has been configured.");
478 if (r <= 0)
479 return r;
480
fe75d5bc
DDM
481 r = dir_fd_is_root(rfd);
482 if (r < 0)
483 return log_error_errno(r, "Failed to check if directory file descriptor is root: %m");
484
485 if (arg_copy_keymap && r == 0) {
0dc39dff 486 r = copy_file_atomic_at(AT_FDCWD, etc_vconsole_conf(), pfd, f, 0644, COPY_REFLINK);
ed457f13
TB
487 if (r != -ENOENT) {
488 if (r < 0)
b352e545 489 return log_error_errno(r, "Failed to copy host's /etc/vconsole.conf: %m");
ed457f13 490
b352e545 491 log_info("Copied host's /etc/vconsole.conf.");
ed457f13
TB
492 return 0;
493 }
494 }
495
0d2cc656 496 r = prompt_keymap(rfd, mute_console_link);
ed457f13
TB
497 if (r == -ENOENT)
498 return 0; /* don't fail if no keymaps are installed */
499 if (r < 0)
500 return r;
501
a7353b4d 502 if (isempty(arg_keymap))
ed457f13
TB
503 return 0;
504
8a008fa7
DDM
505 VCContext vc = {
506 .keymap = arg_keymap,
507 };
508 _cleanup_(x11_context_clear) X11Context xc = {};
509
510 r = vconsole_convert_to_x11(&vc, /* verify= */ NULL, &xc);
511 if (r < 0)
512 return log_error_errno(r, "Failed to convert keymap data: %m");
513
514 r = vconsole_serialize(&vc, &xc, &keymap);
515 if (r < 0)
516 return log_error_errno(r, "Failed to serialize keymap data: %m");
a7353b4d 517
0e7a7cd4 518 r = write_vconsole_conf(pfd, f, keymap);
ed457f13 519 if (r < 0)
b352e545 520 return log_error_errno(r, "Failed to write /etc/vconsole.conf: %m");
ed457f13 521
b352e545 522 log_info("/etc/vconsole.conf written.");
cea32691 523 return 1;
ed457f13
TB
524}
525
fa350969 526static int timezone_is_ok(const char *name, void *userdata) {
87e0eafe 527 return timezone_is_valid(name, LOG_DEBUG);
089fb865
MG
528}
529
0d2cc656 530static int prompt_timezone(int rfd, sd_varlink **mute_console_link) {
418b9be5
LP
531 _cleanup_strv_free_ char **zones = NULL;
532 int r;
533
a0657479
DDM
534 assert(rfd >= 0);
535
418b9be5
LP
536 if (arg_timezone)
537 return 0;
538
416f7b3a
LP
539 r = read_credential("firstboot.timezone", (void**) &arg_timezone, NULL);
540 if (r < 0)
541 log_debug_errno(r, "Failed to read credential firstboot.timezone, ignoring: %m");
542 else {
543 log_debug("Acquired timezone from credential.");
544 return 0;
545 }
546
eb650ffe
ZJS
547 if (!arg_prompt_timezone) {
548 log_debug("Prompting for timezone was not requested.");
418b9be5 549 return 0;
eb650ffe 550 }
418b9be5
LP
551
552 r = get_timezones(&zones);
23bbb0de
MS
553 if (r < 0)
554 return log_error_errno(r, "Cannot query timezone list: %m");
418b9be5 555
0d2cc656 556 print_welcome(rfd, mute_console_link);
418b9be5 557
fa350969
LP
558 return prompt_loop(
559 "Please enter the new timezone name or number",
560 GLYPH_CLOCK,
561 zones,
562 /* accepted= */ NULL,
563 /* ellipsize_percentage= */ 30,
564 /* n_columns= */ 3,
565 /* column_width= */ 20,
566 timezone_is_ok,
567 /* refresh= */ NULL,
568 FD_TO_PTR(rfd),
569 PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
570 &arg_timezone);
418b9be5
LP
571}
572
0d2cc656 573static int process_timezone(int rfd, sd_varlink **mute_console_link) {
b352e545 574 _cleanup_close_ int pfd = -EBADF;
0dc39dff 575 _cleanup_free_ char *f = NULL, *relpath = NULL;
b352e545 576 const char *e;
418b9be5
LP
577 int r;
578
b352e545 579 assert(rfd >= 0);
418b9be5 580
0dc39dff 581 pfd = chase_and_open_parent_at(rfd, etc_localtime(),
b352e545
DDM
582 CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
583 &f);
584 if (pfd < 0)
585 return log_error_errno(pfd, "Failed to chase /etc/localtime: %m");
418b9be5 586
b352e545
DDM
587 r = should_configure(pfd, f);
588 if (r == 0)
589 log_debug("Found /etc/localtime, assuming timezone has been configured.");
590 if (r <= 0)
591 return r;
592
fe75d5bc
DDM
593 r = dir_fd_is_root(rfd);
594 if (r < 0)
595 return log_error_errno(r, "Failed to check if directory file descriptor is root: %m");
596
597 if (arg_copy_timezone && r == 0) {
b352e545
DDM
598 _cleanup_free_ char *s = NULL;
599
0dc39dff 600 r = readlink_malloc(etc_localtime(), &s);
418b9be5 601 if (r != -ENOENT) {
23bbb0de 602 if (r < 0)
b352e545 603 return log_error_errno(r, "Failed to read host's /etc/localtime: %m");
418b9be5 604
9ea5a6e7 605 r = symlinkat_atomic_full(s, pfd, f, SYMLINK_LABEL);
e56dc320 606 if (r < 0)
b352e545 607 return log_error_errno(r, "Failed to create /etc/localtime symlink: %m");
418b9be5 608
b352e545 609 log_info("Copied host's /etc/localtime.");
418b9be5
LP
610 return 0;
611 }
612 }
613
0d2cc656 614 r = prompt_timezone(rfd, mute_console_link);
418b9be5
LP
615 if (r < 0)
616 return r;
617
618 if (isempty(arg_timezone))
619 return 0;
620
0dc39dff
VD
621 e = strjoina("/usr/share/zoneinfo/", arg_timezone);
622 r = path_make_relative_parent(etc_localtime(), e, &relpath);
623 if (r < 0)
624 return r;
418b9be5 625
0dc39dff 626 r = symlinkat_atomic_full(relpath, pfd, f, SYMLINK_LABEL);
e56dc320 627 if (r < 0)
b352e545 628 return log_error_errno(r, "Failed to create /etc/localtime symlink: %m");
418b9be5 629
b352e545 630 log_info("/etc/localtime written");
418b9be5
LP
631 return 0;
632}
633
fa350969 634static int hostname_is_ok(const char *name, void *userdata) {
178d80d7
MF
635 return hostname_is_valid(name, VALID_HOSTNAME_TRAILING_DOT);
636}
637
0d2cc656 638static int prompt_hostname(int rfd, sd_varlink **mute_console_link) {
418b9be5
LP
639 int r;
640
a0657479
DDM
641 assert(rfd >= 0);
642
418b9be5
LP
643 if (arg_hostname)
644 return 0;
645
eb650ffe
ZJS
646 if (!arg_prompt_hostname) {
647 log_debug("Prompting for hostname was not requested.");
418b9be5 648 return 0;
eb650ffe 649 }
418b9be5 650
0d2cc656 651 print_welcome(rfd, mute_console_link);
418b9be5 652
fa350969
LP
653 r = prompt_loop("Please enter the new hostname",
654 GLYPH_LABEL,
655 /* menu= */ NULL,
656 /* accepted= */ NULL,
657 /* ellipsize_percentage= */ 100,
658 /* n_columns= */ 3,
659 /* column_width= */ 20,
660 hostname_is_ok,
661 /* refresh= */ NULL,
662 FD_TO_PTR(rfd),
663 PROMPT_MAY_SKIP,
664 &arg_hostname);
178d80d7
MF
665 if (r < 0)
666 return r;
418b9be5 667
b66a4c15
ZJS
668 if (arg_hostname)
669 hostname_cleanup(arg_hostname);
670
418b9be5
LP
671 return 0;
672}
673
0d2cc656 674static int process_hostname(int rfd, sd_varlink **mute_console_link) {
b352e545
DDM
675 _cleanup_close_ int pfd = -EBADF;
676 _cleanup_free_ char *f = NULL;
418b9be5
LP
677 int r;
678
b352e545
DDM
679 assert(rfd >= 0);
680
0dc39dff 681 pfd = chase_and_open_parent_at(rfd, etc_hostname(),
b352e545
DDM
682 CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN,
683 &f);
684 if (pfd < 0)
685 return log_error_errno(pfd, "Failed to chase /etc/hostname: %m");
686
687 r = should_configure(pfd, f);
688 if (r == 0)
689 log_debug("Found /etc/hostname, assuming hostname has been configured.");
690 if (r <= 0)
691 return r;
418b9be5 692
0d2cc656 693 r = prompt_hostname(rfd, mute_console_link);
418b9be5
LP
694 if (r < 0)
695 return r;
696
697 if (isempty(arg_hostname))
698 return 0;
699
b352e545 700 r = write_string_file_at(pfd, f, arg_hostname,
f6e213e8 701 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
23bbb0de 702 if (r < 0)
b352e545 703 return log_error_errno(r, "Failed to write /etc/hostname: %m");
418b9be5 704
b352e545 705 log_info("/etc/hostname written.");
418b9be5
LP
706 return 0;
707}
708
b352e545
DDM
709static int process_machine_id(int rfd) {
710 _cleanup_close_ int pfd = -EBADF;
711 _cleanup_free_ char *f = NULL;
418b9be5
LP
712 int r;
713
b352e545
DDM
714 assert(rfd >= 0);
715
716 pfd = chase_and_open_parent_at(rfd, "/etc/machine-id",
b39710cc 717 CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
b352e545
DDM
718 &f);
719 if (pfd < 0)
720 return log_error_errno(pfd, "Failed to chase /etc/machine-id: %m");
721
722 r = should_configure(pfd, f);
723 if (r == 0)
724 log_debug("Found /etc/machine-id, assuming machine-id has been configured.");
725 if (r <= 0)
726 return r;
418b9be5 727
eb650ffe
ZJS
728 if (sd_id128_is_null(arg_machine_id)) {
729 log_debug("Initialization of machine-id was not requested, skipping.");
418b9be5 730 return 0;
eb650ffe 731 }
418b9be5 732
b352e545 733 r = write_string_file_at(pfd, "machine-id", SD_ID128_TO_STRING(arg_machine_id),
f6e213e8 734 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
23bbb0de 735 if (r < 0)
c7c1edd6 736 return log_error_errno(r, "Failed to write /etc/machine-id: %m");
418b9be5 737
b352e545 738 log_info("/etc/machine-id written.");
418b9be5
LP
739 return 0;
740}
741
0d2cc656 742static int prompt_root_password(int rfd, sd_varlink **mute_console_link) {
1fbc95d3 743 const char *msg1, *msg2;
418b9be5
LP
744 int r;
745
a0657479
DDM
746 assert(rfd >= 0);
747
418b9be5
LP
748 if (arg_root_password)
749 return 0;
750
ff86850b 751 if (get_credential_user_password("root", &arg_root_password, &arg_root_password_is_hashed) >= 0)
416f7b3a 752 return 0;
416f7b3a 753
eb650ffe
ZJS
754 if (!arg_prompt_root_password) {
755 log_debug("Prompting for root password was not requested.");
418b9be5 756 return 0;
eb650ffe 757 }
418b9be5 758
0d2cc656 759 print_welcome(rfd, mute_console_link);
418b9be5 760
971637c4
LP
761 msg1 = "Please enter the new root password (empty to skip):";
762 msg2 = "Please enter the new root password again:";
418b9be5 763
7baf10a7
LP
764 suggest_passwords();
765
418b9be5 766 for (;;) {
c7b7d74e 767 _cleanup_strv_free_erase_ char **a = NULL, **b = NULL;
7baf10a7 768 _cleanup_free_ char *error = NULL;
418b9be5 769
d08fd4c3 770 AskPasswordRequest req = {
72068d9d 771 .tty_fd = -EBADF,
d08fd4c3 772 .message = msg1,
c4a02a52 773 .until = USEC_INFINITY,
d66894a7 774 .hup_fd = -EBADF,
d08fd4c3
LP
775 };
776
c4a02a52 777 r = ask_password_tty(&req, /* flags= */ 0, &a);
23bbb0de
MS
778 if (r < 0)
779 return log_error_errno(r, "Failed to query root password: %m");
39e96f84
ZJS
780 if (strv_length(a) != 1)
781 return log_error_errno(SYNTHETIC_ERRNO(EIO),
782 "Received multiple passwords, where we expected one.");
418b9be5 783
c7b7d74e 784 if (isempty(*a)) {
3f084827 785 log_info("No password entered, skipping.");
418b9be5
LP
786 break;
787 }
788
de695626 789 r = check_password_quality(*a, /* old = */ NULL, "root", &error);
bb44fd07
ZJS
790 if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
791 log_warning("Password quality check is not supported, proceeding anyway.");
792 else if (r < 0)
793 return log_error_errno(r, "Failed to check password quality: %m");
794 else if (r == 0)
7baf10a7
LP
795 log_warning("Password is weak, accepting anyway: %s", error);
796
d08fd4c3
LP
797 req.message = msg2;
798
c4a02a52 799 r = ask_password_tty(&req, /* flags= */ 0, &b);
ab84f5b9 800 if (r < 0)
00843602 801 return log_error_errno(r, "Failed to query root password: %m");
39e96f84
ZJS
802 if (strv_length(b) != 1)
803 return log_error_errno(SYNTHETIC_ERRNO(EIO),
804 "Received multiple passwords, where we expected one.");
418b9be5 805
c7b7d74e 806 if (!streq(*a, *b)) {
418b9be5 807 log_error("Entered passwords did not match, please try again.");
418b9be5
LP
808 continue;
809 }
810
c7b7d74e 811 arg_root_password = TAKE_PTR(*a);
418b9be5
LP
812 break;
813 }
814
815 return 0;
816}
817
b352e545 818static int find_shell(int rfd, const char *path) {
31363bd5
DDM
819 int r;
820
821 assert(path);
822
823 if (!valid_shell(path))
824 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "%s is not a valid shell", path);
825
b352e545
DDM
826 r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT, NULL, NULL);
827 if (r < 0)
828 return log_error_errno(r, "Failed to resolve shell %s: %m", path);
31363bd5
DDM
829
830 return 0;
831}
832
fa350969
LP
833static int shell_is_ok(const char *path, void *userdata) {
834 int rfd = ASSERT_FD(PTR_TO_FD(userdata));
178d80d7
MF
835
836 return find_shell(rfd, path) >= 0;
837}
838
0d2cc656 839static int prompt_root_shell(int rfd, sd_varlink **mute_console_link) {
28900a1b
DDM
840 int r;
841
a0657479
DDM
842 assert(rfd >= 0);
843
416f7b3a
LP
844 if (arg_root_shell)
845 return 0;
846
847 r = read_credential("passwd.shell.root", (void**) &arg_root_shell, NULL);
848 if (r < 0)
849 log_debug_errno(r, "Failed to read credential passwd.shell.root, ignoring: %m");
850 else {
851 log_debug("Acquired root shell from credential.");
852 return 0;
853 }
854
eb650ffe
ZJS
855 if (!arg_prompt_root_shell) {
856 log_debug("Prompting for root shell was not requested.");
28900a1b 857 return 0;
eb650ffe 858 }
28900a1b 859
0d2cc656 860 print_welcome(rfd, mute_console_link);
28900a1b 861
fa350969
LP
862 return prompt_loop(
863 "Please enter the new root shell",
864 GLYPH_SHELL,
865 /* menu= */ NULL,
866 /* accepted= */ NULL,
867 /* ellipsize_percentage= */ 0,
868 /* n_columns= */ 3,
869 /* column_width= */ 20,
870 shell_is_ok,
871 /* refresh= */ NULL,
872 FD_TO_PTR(rfd),
873 PROMPT_MAY_SKIP,
874 &arg_root_shell);
28900a1b
DDM
875}
876
a0657479 877static int write_root_passwd(int rfd, int etc_fd, const char *password, const char *shell) {
4926ceaf
DDM
878 _cleanup_fclose_ FILE *original = NULL, *passwd = NULL;
879 _cleanup_(unlink_and_freep) char *passwd_tmp = NULL;
880 int r;
2319154a 881 bool found = false;
4926ceaf 882
b352e545 883 r = fopen_temporary_at_label(etc_fd, "passwd", "passwd", &passwd, &passwd_tmp);
4926ceaf
DDM
884 if (r < 0)
885 return r;
886
b352e545
DDM
887 r = xfopenat(etc_fd, "passwd", "re", O_NOFOLLOW, &original);
888 if (r < 0 && r != -ENOENT)
889 return r;
890
4926ceaf
DDM
891 if (original) {
892 struct passwd *i;
893
bb72c434 894 r = copy_rights(fileno(original), fileno(passwd));
4926ceaf
DDM
895 if (r < 0)
896 return r;
897
898 while ((r = fgetpwent_sane(original, &i)) > 0) {
899
28900a1b 900 if (streq(i->pw_name, "root")) {
35bc4c34
DN
901 if (password)
902 i->pw_passwd = (char *) password;
28900a1b
DDM
903 if (shell)
904 i->pw_shell = (char *) shell;
2319154a 905 found = true;
28900a1b 906 }
4926ceaf
DDM
907
908 r = putpwent_sane(i, passwd);
909 if (r < 0)
910 return r;
911 }
912 if (r < 0)
913 return r;
914
915 } else {
2319154a
DN
916 r = fchmod(fileno(passwd), 0644);
917 if (r < 0)
918 return -errno;
919 }
920
921 if (!found) {
4926ceaf
DDM
922 struct passwd root = {
923 .pw_name = (char *) "root",
35bc4c34 924 .pw_passwd = (char *) (password ?: PASSWORD_SEE_SHADOW),
4926ceaf
DDM
925 .pw_uid = 0,
926 .pw_gid = 0,
927 .pw_gecos = (char *) "Super User",
928 .pw_dir = (char *) "/root",
a0657479 929 .pw_shell = (char *) (shell ?: default_root_shell_at(rfd)),
4926ceaf
DDM
930 };
931
932 if (errno != ENOENT)
933 return -errno;
934
4926ceaf
DDM
935 r = putpwent_sane(&root, passwd);
936 if (r < 0)
937 return r;
938 }
939
940 r = fflush_sync_and_check(passwd);
941 if (r < 0)
942 return r;
943
b352e545 944 r = renameat_and_apply_smack_floor_label(etc_fd, passwd_tmp, etc_fd, "passwd");
4926ceaf
DDM
945 if (r < 0)
946 return r;
947
948 return 0;
949}
950
b352e545 951static int write_root_shadow(int etc_fd, const char *hashed_password) {
b4909a3f
DDM
952 _cleanup_fclose_ FILE *original = NULL, *shadow = NULL;
953 _cleanup_(unlink_and_freep) char *shadow_tmp = NULL;
100d5f6e 954 int r;
2319154a 955 bool found = false;
100d5f6e 956
b352e545 957 r = fopen_temporary_at_label(etc_fd, "shadow", "shadow", &shadow, &shadow_tmp);
b4909a3f
DDM
958 if (r < 0)
959 return r;
960
b352e545
DDM
961 r = xfopenat(etc_fd, "shadow", "re", O_NOFOLLOW, &original);
962 if (r < 0 && r != -ENOENT)
963 return r;
964
b4909a3f
DDM
965 if (original) {
966 struct spwd *i;
967
bb72c434 968 r = copy_rights(fileno(original), fileno(shadow));
b4909a3f
DDM
969 if (r < 0)
970 return r;
971
972 while ((r = fgetspent_sane(original, &i)) > 0) {
973
974 if (streq(i->sp_namp, "root")) {
35bc4c34
DN
975 if (hashed_password) {
976 i->sp_pwdp = (char *) hashed_password;
977 i->sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
978 }
2319154a 979 found = true;
b4909a3f
DDM
980 }
981
982 r = putspent_sane(i, shadow);
983 if (r < 0)
984 return r;
985 }
986 if (r < 0)
987 return r;
988
989 } else {
2319154a
DN
990 r = fchmod(fileno(shadow), 0000);
991 if (r < 0)
992 return -errno;
993 }
994
995 if (!found) {
b4909a3f
DDM
996 struct spwd root = {
997 .sp_namp = (char*) "root",
35bc4c34 998 .sp_pwdp = (char *) (hashed_password ?: PASSWORD_LOCKED_AND_INVALID),
b4909a3f
DDM
999 .sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY),
1000 .sp_min = -1,
1001 .sp_max = -1,
1002 .sp_warn = -1,
1003 .sp_inact = -1,
1004 .sp_expire = -1,
f5fbe71d 1005 .sp_flag = ULONG_MAX, /* this appears to be what everybody does ... */
b4909a3f
DDM
1006 };
1007
1008 if (errno != ENOENT)
1009 return -errno;
418b9be5 1010
b4909a3f
DDM
1011 r = putspent_sane(&root, shadow);
1012 if (r < 0)
1013 return r;
1014 }
1015
1016 r = fflush_sync_and_check(shadow);
100d5f6e
FB
1017 if (r < 0)
1018 return r;
418b9be5 1019
b352e545 1020 r = renameat_and_apply_smack_floor_label(etc_fd, shadow_tmp, etc_fd, "shadow");
b4909a3f
DDM
1021 if (r < 0)
1022 return r;
1023
1024 return 0;
418b9be5
LP
1025}
1026
0d2cc656 1027static int process_root_account(int rfd, sd_varlink **mute_console_link) {
b352e545
DDM
1028 _cleanup_close_ int pfd = -EBADF;
1029 _cleanup_(release_lock_file) LockFile lock = LOCK_FILE_INIT;
0e98d17e 1030 _cleanup_(erase_and_freep) char *_hashed_password = NULL;
c4a53ebf 1031 const char *password, *hashed_password;
b352e545
DDM
1032 int k = 0, r;
1033
1034 assert(rfd >= 0);
1035
1036 pfd = chase_and_open_parent_at(rfd, "/etc/passwd",
1037 CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
1038 NULL);
1039 if (pfd < 0)
1040 return log_error_errno(pfd, "Failed to chase /etc/passwd: %m");
1041
1042 /* Ensure that passwd and shadow are in the same directory and are not symlinks. */
1043
1044 FOREACH_STRING(s, "passwd", "shadow") {
1045 r = verify_regular_at(pfd, s, /* follow = */ false);
b352e545 1046 if (r < 0 && r != -ENOENT)
2560dcbf 1047 return log_error_errno(r, "Verification of /etc/%s being regular file failed: %m", s);
b352e545
DDM
1048
1049 r = should_configure(pfd, s);
1050 if (r < 0)
1051 return r;
418b9be5 1052
b352e545
DDM
1053 k += r;
1054 }
c4a53ebf 1055
b352e545
DDM
1056 if (k == 0) {
1057 log_debug("Found /etc/passwd and /etc/shadow, assuming root account has been initialized.");
418b9be5 1058 return 0;
eb650ffe 1059 }
87a3a4a8 1060
fe585662 1061 r = make_lock_file_at(pfd, ETC_PASSWD_LOCK_FILENAME, LOCK_EX, &lock);
b352e545
DDM
1062 if (r < 0)
1063 return log_error_errno(r, "Failed to take a lock on /etc/passwd: %m");
4926ceaf 1064
fe75d5bc
DDM
1065 k = dir_fd_is_root(rfd);
1066 if (k < 0)
1067 return log_error_errno(k, "Failed to check if directory file descriptor is root: %m");
1068
1069 if (arg_copy_root_shell && k == 0) {
75673cd8 1070 _cleanup_free_ struct passwd *p = NULL;
28900a1b 1071
75673cd8
LP
1072 r = getpwnam_malloc("root", &p);
1073 if (r < 0)
1074 return log_error_errno(r, "Failed to find passwd entry for root: %m");
28900a1b
DDM
1075
1076 r = free_and_strdup(&arg_root_shell, p->pw_shell);
1077 if (r < 0)
1078 return log_oom();
1079 }
1080
0d2cc656 1081 r = prompt_root_shell(rfd, mute_console_link);
28900a1b
DDM
1082 if (r < 0)
1083 return r;
1084
fe75d5bc 1085 if (arg_copy_root_password && k == 0) {
418b9be5
LP
1086 struct spwd *p;
1087
1088 errno = 0;
1089 p = getspnam("root");
c4a53ebf
DDM
1090 if (!p)
1091 return log_error_errno(errno_or_else(EIO), "Failed to find shadow entry for root: %m");
418b9be5 1092
c4a53ebf
DDM
1093 r = free_and_strdup(&arg_root_password, p->sp_pwdp);
1094 if (r < 0)
1095 return log_oom();
418b9be5 1096
c4a53ebf 1097 arg_root_password_is_hashed = true;
418b9be5
LP
1098 }
1099
0d2cc656 1100 r = prompt_root_password(rfd, mute_console_link);
418b9be5
LP
1101 if (r < 0)
1102 return r;
1103
c4a53ebf 1104 if (arg_root_password && arg_root_password_is_hashed) {
53c25ac9 1105 password = PASSWORD_SEE_SHADOW;
676339a1 1106 hashed_password = arg_root_password;
c4a53ebf 1107 } else if (arg_root_password) {
0e98d17e
ZJS
1108 r = hash_password(arg_root_password, &_hashed_password);
1109 if (r < 0)
1110 return log_error_errno(r, "Failed to hash password: %m");
676339a1 1111
53c25ac9 1112 password = PASSWORD_SEE_SHADOW;
0e98d17e 1113 hashed_password = _hashed_password;
c4a53ebf 1114
5088de9d
DN
1115 } else if (arg_delete_root_password) {
1116 password = PASSWORD_SEE_SHADOW;
1117 hashed_password = PASSWORD_NONE;
35bc4c34
DN
1118 } else if (!arg_root_password && arg_prompt_root_password) {
1119 /* If the user was prompted, but no password was supplied, lock the account. */
5088de9d
DN
1120 password = PASSWORD_SEE_SHADOW;
1121 hashed_password = PASSWORD_LOCKED_AND_INVALID;
35bc4c34
DN
1122 } else
1123 /* Leave the password as is. */
1124 password = hashed_password = NULL;
1125
1126 /* Don't create/modify passwd and shadow if there's nothing to do. */
1127 if (!(password || hashed_password || arg_root_shell)) {
1128 log_debug("Initialization of root account was not requested, skipping.");
1129 return 0;
5088de9d 1130 }
c4a53ebf 1131
a0657479 1132 r = write_root_passwd(rfd, pfd, password, arg_root_shell);
c4a53ebf 1133 if (r < 0)
b352e545 1134 return log_error_errno(r, "Failed to write /etc/passwd: %m");
c4a53ebf 1135
b352e545 1136 log_info("/etc/passwd written.");
418b9be5 1137
b352e545 1138 r = write_root_shadow(pfd, hashed_password);
23bbb0de 1139 if (r < 0)
b352e545 1140 return log_error_errno(r, "Failed to write /etc/shadow: %m");
418b9be5 1141
b352e545 1142 log_info("/etc/shadow written.");
418b9be5
LP
1143 return 0;
1144}
1145
b352e545
DDM
1146static int process_kernel_cmdline(int rfd) {
1147 _cleanup_close_ int pfd = -EBADF;
1148 _cleanup_free_ char *f = NULL;
a5925354
DDM
1149 int r;
1150
b352e545
DDM
1151 assert(rfd >= 0);
1152
1153 pfd = chase_and_open_parent_at(rfd, "/etc/kernel/cmdline",
b39710cc 1154 CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
b352e545
DDM
1155 &f);
1156 if (pfd < 0)
1157 return log_error_errno(pfd, "Failed to chase /etc/kernel/cmdline: %m");
1158
1159 r = should_configure(pfd, f);
1160 if (r == 0)
1161 log_debug("Found /etc/kernel/cmdline, assuming kernel command line has been configured.");
1162 if (r <= 0)
1163 return r;
a5925354 1164
eb650ffe
ZJS
1165 if (!arg_kernel_cmdline) {
1166 log_debug("Creation of /etc/kernel/cmdline was not requested, skipping.");
a5925354 1167 return 0;
eb650ffe 1168 }
a5925354 1169
b352e545 1170 r = write_string_file_at(pfd, "cmdline", arg_kernel_cmdline,
f6e213e8 1171 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
a5925354 1172 if (r < 0)
b352e545 1173 return log_error_errno(r, "Failed to write /etc/kernel/cmdline: %m");
a5925354 1174
b352e545 1175 log_info("/etc/kernel/cmdline written.");
a5925354
DDM
1176 return 0;
1177}
1178
05eb2c60
DDM
1179static int reset_one(int rfd, const char *path) {
1180 _cleanup_close_ int pfd = -EBADF;
1181 _cleanup_free_ char *f = NULL;
1182
1183 assert(rfd >= 0);
1184 assert(path);
1185
1186 pfd = chase_and_open_parent_at(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_WARN|CHASE_NOFOLLOW, &f);
1187 if (pfd == -ENOENT)
1188 return 0;
1189 if (pfd < 0)
1190 return log_error_errno(pfd, "Failed to resolve %s: %m", path);
1191
1192 if (unlinkat(pfd, f, 0) < 0)
1193 return errno == ENOENT ? 0 : log_error_errno(errno, "Failed to remove %s: %m", path);
1194
1195 log_info("Removed %s", path);
1196 return 0;
1197}
1198
1199static int process_reset(int rfd) {
1200 int r;
1201
1202 assert(rfd >= 0);
1203
1204 if (!arg_reset)
1205 return 0;
1206
1207 FOREACH_STRING(p,
0dc39dff
VD
1208 etc_locale_conf(),
1209 etc_vconsole_conf(),
1210 etc_hostname(),
05eb2c60 1211 "/etc/machine-id",
cd320749 1212 "/etc/kernel/cmdline",
0dc39dff 1213 etc_localtime()) {
05eb2c60
DDM
1214 r = reset_one(rfd, p);
1215 if (r < 0)
1216 return r;
1217 }
1218
1219 return 0;
1220}
1221
37ec0fdd
LP
1222static int help(void) {
1223 _cleanup_free_ char *link = NULL;
1224 int r;
1225
1226 r = terminal_urlify_man("systemd-firstboot", "1", &link);
1227 if (r < 0)
1228 return log_oom();
1229
875a618e
LP
1230 printf("%1$s [OPTIONS...]\n"
1231 "\n%3$sConfigures basic settings of the system.%4$s\n\n"
e16793ee
ZJS
1232 " -h --help Show this help\n"
1233 " --version Show package version\n"
1234 " --root=PATH Operate on an alternate filesystem root\n"
84be0c71
LP
1235 " --image=PATH Operate on disk image as filesystem root\n"
1236 " --image-policy=POLICY Specify disk image dissection policy\n"
e16793ee
ZJS
1237 " --locale=LOCALE Set primary locale (LANG=)\n"
1238 " --locale-messages=LOCALE Set message locale (LC_MESSAGES=)\n"
1239 " --keymap=KEYMAP Set keymap\n"
1240 " --timezone=TIMEZONE Set timezone\n"
1241 " --hostname=NAME Set hostname\n"
fd6ee7ed 1242 " --setup-machine-id Set a random machine ID\n"
981644ed 1243 " --machine-id=ID Set specified machine ID\n"
e16793ee
ZJS
1244 " --root-password=PASSWORD Set root password from plaintext password\n"
1245 " --root-password-file=FILE Set root password from file\n"
1246 " --root-password-hashed=HASH Set root password from hashed password\n"
1247 " --root-shell=SHELL Set root shell\n"
981644ed
AAF
1248 " --kernel-command-line=CMDLINE\n"
1249 " Set kernel command line\n"
e16793ee
ZJS
1250 " --prompt-locale Prompt the user for locale settings\n"
1251 " --prompt-keymap Prompt the user for keymap settings\n"
aa27bec1
LP
1252 " --prompt-keymap-auto Prompt the user for keymap settings if invoked\n"
1253 " on local console\n"
e16793ee
ZJS
1254 " --prompt-timezone Prompt the user for timezone\n"
1255 " --prompt-hostname Prompt the user for hostname\n"
1256 " --prompt-root-password Prompt the user for root password\n"
1257 " --prompt-root-shell Prompt the user for root shell\n"
1258 " --prompt Prompt for all of the above\n"
1259 " --copy-locale Copy locale from host\n"
1260 " --copy-keymap Copy keymap from host\n"
1261 " --copy-timezone Copy timezone from host\n"
1262 " --copy-root-password Copy root password from host\n"
1263 " --copy-root-shell Copy root shell from host\n"
1264 " --copy Copy locale, keymap, timezone, root password\n"
e16793ee
ZJS
1265 " --force Overwrite existing files\n"
1266 " --delete-root-password Delete root password\n"
1267 " --welcome=no Disable the welcome text\n"
73ee723a
LP
1268 " --chrome=no Don't show color bar at top and bottom of\n"
1269 " terminal\n"
0d2cc656
LP
1270 " --mute-console=yes Tell kernel/PID 1 to not write to the console\n"
1271 " while running\n"
05eb2c60 1272 " --reset Remove existing files\n"
875a618e 1273 "\nSee the %2$s for details.\n",
bc556335 1274 program_invocation_short_name,
875a618e
LP
1275 link,
1276 ansi_highlight(),
1277 ansi_normal());
37ec0fdd
LP
1278
1279 return 0;
418b9be5
LP
1280}
1281
1282static int parse_argv(int argc, char *argv[]) {
1283
1284 enum {
1285 ARG_VERSION = 0x100,
1286 ARG_ROOT,
3ff9fa59 1287 ARG_IMAGE,
06e78680 1288 ARG_IMAGE_POLICY,
418b9be5
LP
1289 ARG_LOCALE,
1290 ARG_LOCALE_MESSAGES,
ed457f13 1291 ARG_KEYMAP,
418b9be5
LP
1292 ARG_TIMEZONE,
1293 ARG_HOSTNAME,
fd6ee7ed 1294 ARG_SETUP_MACHINE_ID,
418b9be5
LP
1295 ARG_MACHINE_ID,
1296 ARG_ROOT_PASSWORD,
1297 ARG_ROOT_PASSWORD_FILE,
676339a1 1298 ARG_ROOT_PASSWORD_HASHED,
28900a1b 1299 ARG_ROOT_SHELL,
a5925354 1300 ARG_KERNEL_COMMAND_LINE,
418b9be5
LP
1301 ARG_PROMPT,
1302 ARG_PROMPT_LOCALE,
ed457f13 1303 ARG_PROMPT_KEYMAP,
aa27bec1 1304 ARG_PROMPT_KEYMAP_AUTO,
418b9be5
LP
1305 ARG_PROMPT_TIMEZONE,
1306 ARG_PROMPT_HOSTNAME,
1307 ARG_PROMPT_ROOT_PASSWORD,
28900a1b 1308 ARG_PROMPT_ROOT_SHELL,
418b9be5
LP
1309 ARG_COPY,
1310 ARG_COPY_LOCALE,
ed457f13 1311 ARG_COPY_KEYMAP,
418b9be5
LP
1312 ARG_COPY_TIMEZONE,
1313 ARG_COPY_ROOT_PASSWORD,
28900a1b 1314 ARG_COPY_ROOT_SHELL,
b4909a3f 1315 ARG_FORCE,
4926ceaf 1316 ARG_DELETE_ROOT_PASSWORD,
a1225020 1317 ARG_WELCOME,
73ee723a 1318 ARG_CHROME,
05eb2c60 1319 ARG_RESET,
0d2cc656 1320 ARG_MUTE_CONSOLE,
418b9be5
LP
1321 };
1322
1323 static const struct option options[] = {
676339a1
DDM
1324 { "help", no_argument, NULL, 'h' },
1325 { "version", no_argument, NULL, ARG_VERSION },
1326 { "root", required_argument, NULL, ARG_ROOT },
3ff9fa59 1327 { "image", required_argument, NULL, ARG_IMAGE },
06e78680 1328 { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY },
676339a1
DDM
1329 { "locale", required_argument, NULL, ARG_LOCALE },
1330 { "locale-messages", required_argument, NULL, ARG_LOCALE_MESSAGES },
1331 { "keymap", required_argument, NULL, ARG_KEYMAP },
1332 { "timezone", required_argument, NULL, ARG_TIMEZONE },
1333 { "hostname", required_argument, NULL, ARG_HOSTNAME },
fd6ee7ed 1334 { "setup-machine-id", no_argument, NULL, ARG_SETUP_MACHINE_ID },
676339a1
DDM
1335 { "machine-id", required_argument, NULL, ARG_MACHINE_ID },
1336 { "root-password", required_argument, NULL, ARG_ROOT_PASSWORD },
1337 { "root-password-file", required_argument, NULL, ARG_ROOT_PASSWORD_FILE },
1338 { "root-password-hashed", required_argument, NULL, ARG_ROOT_PASSWORD_HASHED },
28900a1b 1339 { "root-shell", required_argument, NULL, ARG_ROOT_SHELL },
a5925354 1340 { "kernel-command-line", required_argument, NULL, ARG_KERNEL_COMMAND_LINE },
676339a1
DDM
1341 { "prompt", no_argument, NULL, ARG_PROMPT },
1342 { "prompt-locale", no_argument, NULL, ARG_PROMPT_LOCALE },
1343 { "prompt-keymap", no_argument, NULL, ARG_PROMPT_KEYMAP },
aa27bec1 1344 { "prompt-keymap-auto", no_argument, NULL, ARG_PROMPT_KEYMAP_AUTO },
676339a1
DDM
1345 { "prompt-timezone", no_argument, NULL, ARG_PROMPT_TIMEZONE },
1346 { "prompt-hostname", no_argument, NULL, ARG_PROMPT_HOSTNAME },
1347 { "prompt-root-password", no_argument, NULL, ARG_PROMPT_ROOT_PASSWORD },
28900a1b 1348 { "prompt-root-shell", no_argument, NULL, ARG_PROMPT_ROOT_SHELL },
676339a1
DDM
1349 { "copy", no_argument, NULL, ARG_COPY },
1350 { "copy-locale", no_argument, NULL, ARG_COPY_LOCALE },
1351 { "copy-keymap", no_argument, NULL, ARG_COPY_KEYMAP },
1352 { "copy-timezone", no_argument, NULL, ARG_COPY_TIMEZONE },
1353 { "copy-root-password", no_argument, NULL, ARG_COPY_ROOT_PASSWORD },
28900a1b 1354 { "copy-root-shell", no_argument, NULL, ARG_COPY_ROOT_SHELL },
676339a1
DDM
1355 { "force", no_argument, NULL, ARG_FORCE },
1356 { "delete-root-password", no_argument, NULL, ARG_DELETE_ROOT_PASSWORD },
a1225020 1357 { "welcome", required_argument, NULL, ARG_WELCOME },
73ee723a 1358 { "chrome", required_argument, NULL, ARG_CHROME },
05eb2c60 1359 { "reset", no_argument, NULL, ARG_RESET },
0d2cc656 1360 { "mute-console", required_argument, NULL, ARG_MUTE_CONSOLE },
418b9be5
LP
1361 {}
1362 };
1363
1364 int r, c;
1365
1366 assert(argc >= 0);
1367 assert(argv);
1368
601185b4 1369 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
418b9be5
LP
1370
1371 switch (c) {
1372
1373 case 'h':
37ec0fdd 1374 return help();
418b9be5
LP
1375
1376 case ARG_VERSION:
3f6fd1ba 1377 return version();
418b9be5
LP
1378
1379 case ARG_ROOT:
614b022c 1380 r = parse_path_argument(optarg, true, &arg_root);
0f474365 1381 if (r < 0)
0f03c2a4 1382 return r;
418b9be5
LP
1383 break;
1384
3ff9fa59 1385 case ARG_IMAGE:
614b022c 1386 r = parse_path_argument(optarg, false, &arg_image);
3ff9fa59
LP
1387 if (r < 0)
1388 return r;
1389 break;
1390
06e78680
YW
1391 case ARG_IMAGE_POLICY:
1392 r = parse_image_policy_argument(optarg, &arg_image_policy);
1393 if (r < 0)
1394 return r;
1395 break;
1396
418b9be5 1397 case ARG_LOCALE:
2fc09a9c
DM
1398 r = free_and_strdup(&arg_locale, optarg);
1399 if (r < 0)
418b9be5
LP
1400 return log_oom();
1401
1402 break;
1403
1404 case ARG_LOCALE_MESSAGES:
2fc09a9c
DM
1405 r = free_and_strdup(&arg_locale_messages, optarg);
1406 if (r < 0)
418b9be5
LP
1407 return log_oom();
1408
1409 break;
1410
ed457f13 1411 case ARG_KEYMAP:
baaa35ad
ZJS
1412 if (!keymap_is_valid(optarg))
1413 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1414 "Keymap %s is not valid.", optarg);
ed457f13
TB
1415
1416 r = free_and_strdup(&arg_keymap, optarg);
1417 if (r < 0)
1418 return log_oom();
1419
1420 break;
1421
418b9be5 1422 case ARG_TIMEZONE:
baaa35ad
ZJS
1423 if (!timezone_is_valid(optarg, LOG_ERR))
1424 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1425 "Timezone %s is not valid.", optarg);
418b9be5 1426
2fc09a9c
DM
1427 r = free_and_strdup(&arg_timezone, optarg);
1428 if (r < 0)
418b9be5
LP
1429 return log_oom();
1430
1431 break;
1432
1433 case ARG_ROOT_PASSWORD:
2fc09a9c
DM
1434 r = free_and_strdup(&arg_root_password, optarg);
1435 if (r < 0)
418b9be5 1436 return log_oom();
676339a1
DDM
1437
1438 arg_root_password_is_hashed = false;
418b9be5
LP
1439 break;
1440
1441 case ARG_ROOT_PASSWORD_FILE:
0da16248 1442 arg_root_password = mfree(arg_root_password);
418b9be5
LP
1443
1444 r = read_one_line_file(optarg, &arg_root_password);
23bbb0de
MS
1445 if (r < 0)
1446 return log_error_errno(r, "Failed to read %s: %m", optarg);
418b9be5 1447
676339a1
DDM
1448 arg_root_password_is_hashed = false;
1449 break;
1450
1451 case ARG_ROOT_PASSWORD_HASHED:
1452 r = free_and_strdup(&arg_root_password, optarg);
1453 if (r < 0)
1454 return log_oom();
1455
1456 arg_root_password_is_hashed = true;
418b9be5
LP
1457 break;
1458
28900a1b 1459 case ARG_ROOT_SHELL:
28900a1b
DDM
1460 r = free_and_strdup(&arg_root_shell, optarg);
1461 if (r < 0)
1462 return log_oom();
1463
1464 break;
1465
418b9be5 1466 case ARG_HOSTNAME:
af9c45d5 1467 if (!hostname_is_valid(optarg, VALID_HOSTNAME_TRAILING_DOT|VALID_HOSTNAME_QUESTION_MARK))
baaa35ad
ZJS
1468 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1469 "Host name %s is not valid.", optarg);
418b9be5 1470
2fc09a9c
DM
1471 r = free_and_strdup(&arg_hostname, optarg);
1472 if (r < 0)
418b9be5
LP
1473 return log_oom();
1474
79485fc2 1475 hostname_cleanup(arg_hostname);
418b9be5
LP
1476 break;
1477
fd6ee7ed
ZJS
1478 case ARG_SETUP_MACHINE_ID:
1479 r = sd_id128_randomize(&arg_machine_id);
1480 if (r < 0)
1481 return log_error_errno(r, "Failed to generate randomized machine ID: %m");
1482
1483 break;
1484
418b9be5 1485 case ARG_MACHINE_ID:
7fb1d980
YW
1486 r = sd_id128_from_string(optarg, &arg_machine_id);
1487 if (r < 0)
1488 return log_error_errno(r, "Failed to parse machine id %s.", optarg);
418b9be5
LP
1489
1490 break;
1491
a5925354
DDM
1492 case ARG_KERNEL_COMMAND_LINE:
1493 r = free_and_strdup(&arg_kernel_cmdline, optarg);
1494 if (r < 0)
1495 return log_oom();
1496
1497 break;
1498
418b9be5 1499 case ARG_PROMPT:
28900a1b
DDM
1500 arg_prompt_locale = arg_prompt_keymap = arg_prompt_timezone = arg_prompt_hostname =
1501 arg_prompt_root_password = arg_prompt_root_shell = true;
aa27bec1 1502 arg_prompt_keymap_auto = false;
418b9be5
LP
1503 break;
1504
1505 case ARG_PROMPT_LOCALE:
1506 arg_prompt_locale = true;
1507 break;
1508
ed457f13
TB
1509 case ARG_PROMPT_KEYMAP:
1510 arg_prompt_keymap = true;
aa27bec1
LP
1511 arg_prompt_keymap_auto = false;
1512 break;
1513
1514 case ARG_PROMPT_KEYMAP_AUTO:
1515 arg_prompt_keymap_auto = true;
ed457f13
TB
1516 break;
1517
418b9be5
LP
1518 case ARG_PROMPT_TIMEZONE:
1519 arg_prompt_timezone = true;
1520 break;
1521
1522 case ARG_PROMPT_HOSTNAME:
1523 arg_prompt_hostname = true;
1524 break;
1525
1526 case ARG_PROMPT_ROOT_PASSWORD:
1527 arg_prompt_root_password = true;
1528 break;
1529
28900a1b
DDM
1530 case ARG_PROMPT_ROOT_SHELL:
1531 arg_prompt_root_shell = true;
1532 break;
1533
418b9be5 1534 case ARG_COPY:
28900a1b
DDM
1535 arg_copy_locale = arg_copy_keymap = arg_copy_timezone = arg_copy_root_password =
1536 arg_copy_root_shell = true;
e926f647 1537 break;
418b9be5
LP
1538
1539 case ARG_COPY_LOCALE:
1540 arg_copy_locale = true;
1541 break;
1542
ed457f13
TB
1543 case ARG_COPY_KEYMAP:
1544 arg_copy_keymap = true;
1545 break;
1546
418b9be5
LP
1547 case ARG_COPY_TIMEZONE:
1548 arg_copy_timezone = true;
1549 break;
1550
1551 case ARG_COPY_ROOT_PASSWORD:
1552 arg_copy_root_password = true;
1553 break;
1554
28900a1b
DDM
1555 case ARG_COPY_ROOT_SHELL:
1556 arg_copy_root_shell = true;
1557 break;
1558
b4909a3f
DDM
1559 case ARG_FORCE:
1560 arg_force = true;
1561 break;
1562
4926ceaf
DDM
1563 case ARG_DELETE_ROOT_PASSWORD:
1564 arg_delete_root_password = true;
1565 break;
1566
a1225020
LP
1567 case ARG_WELCOME:
1568 r = parse_boolean(optarg);
1569 if (r < 0)
1570 return log_error_errno(r, "Failed to parse --welcome= argument: %s", optarg);
1571
1572 arg_welcome = r;
1573 break;
1574
73ee723a
LP
1575 case ARG_CHROME:
1576 r = parse_boolean_argument("--chrome=", optarg, &arg_chrome);
1577 if (r < 0)
1578 return r;
1579
1580 break;
1581
05eb2c60
DDM
1582 case ARG_RESET:
1583 arg_reset = true;
1584 break;
1585
0d2cc656
LP
1586 case ARG_MUTE_CONSOLE:
1587 r = parse_boolean_argument("--mute-console=", optarg, &arg_mute_console);
1588 if (r < 0)
1589 return r;
1590
1591 break;
1592
418b9be5
LP
1593 case '?':
1594 return -EINVAL;
1595
1596 default:
04499a70 1597 assert_not_reached();
418b9be5 1598 }
418b9be5 1599
4926ceaf
DDM
1600 if (arg_delete_root_password && (arg_copy_root_password || arg_root_password || arg_prompt_root_password))
1601 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
fd6ee7ed 1602 "--delete-root-password cannot be combined with other root password options.");
4926ceaf 1603
3ff9fa59 1604 if (arg_image && arg_root)
fd6ee7ed
ZJS
1605 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1606 "--root= and --image= cannot be used together.");
1607
1608 if (!sd_id128_is_null(arg_machine_id) && !(arg_image || arg_root) && !arg_force)
1609 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1610 "--machine-id=/--setup-machine-id only works with --root= or --image=.");
3ff9fa59 1611
418b9be5
LP
1612 return 1;
1613}
1614
d0c50d8d 1615static int reload_system_manager(sd_bus **bus) {
d0c50d8d
ZJS
1616 int r;
1617
1618 assert(bus);
1619
1620 if (!*bus) {
1621 r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, RUNTIME_SCOPE_SYSTEM, bus);
1622 if (r < 0)
d8a77d55 1623 return bus_log_connect_error(r, BUS_TRANSPORT_LOCAL, RUNTIME_SCOPE_SYSTEM);
d0c50d8d
ZJS
1624 }
1625
a9399358 1626 r = bus_service_manager_reload(*bus);
d0c50d8d 1627 if (r < 0)
a9399358
LP
1628 return r;
1629
d0c50d8d
ZJS
1630 log_info("Requested manager reload to apply locale configuration.");
1631 return 0;
1632}
1633
cea32691
ZJS
1634static int reload_vconsole(sd_bus **bus) {
1635 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
8eb668b9
ZJS
1636 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1637 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
1638 const char *object;
cea32691
ZJS
1639 int r;
1640
1641 assert(bus);
1642
1643 if (!*bus) {
1644 r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, RUNTIME_SCOPE_SYSTEM, bus);
1645 if (r < 0)
d8a77d55 1646 return bus_log_connect_error(r, BUS_TRANSPORT_LOCAL, RUNTIME_SCOPE_SYSTEM);
cea32691
ZJS
1647 }
1648
8eb668b9
ZJS
1649 r = bus_wait_for_jobs_new(*bus, &w);
1650 if (r < 0)
1651 return log_error_errno(r, "Could not watch jobs: %m");
1652
1653 r = bus_call_method(*bus, bus_systemd_mgr, "RestartUnit", &error, &reply,
1654 "ss", "systemd-vconsole-setup.service", "replace");
cea32691
ZJS
1655 if (r < 0)
1656 return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
8eb668b9
ZJS
1657
1658 r = sd_bus_message_read(reply, "o", &object);
1659 if (r < 0)
1660 return bus_log_parse_error(r);
1661
e22ad53d 1662 r = bus_wait_for_jobs_one(w, object, BUS_WAIT_JOBS_LOG_ERROR, NULL);
8eb668b9
ZJS
1663 if (r < 0)
1664 return log_error_errno(r, "Failed to wait for systemd-vconsole-setup.service/restart: %m");
cea32691
ZJS
1665 return 0;
1666}
1667
45f39418 1668static int run(int argc, char *argv[]) {
cea32691 1669 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
3ff9fa59 1670 _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
a4b3e942 1671 _cleanup_(umount_and_freep) char *mounted_dir = NULL;
b352e545 1672 _cleanup_close_ int rfd = -EBADF;
418b9be5
LP
1673 int r;
1674
1675 r = parse_argv(argc, argv);
1676 if (r <= 0)
45f39418 1677 return r;
418b9be5 1678
d2acb93d 1679 log_setup();
418b9be5
LP
1680
1681 umask(0022);
1682
cea32691 1683 bool offline = arg_root || arg_image;
3ff9fa59 1684
cea32691 1685 if (!offline) {
3ff9fa59
LP
1686 /* If we are called without --root=/--image= let's honour the systemd.firstboot kernel
1687 * command line option, because we are called to provision the host with basic settings (as
1688 * opposed to some other file system tree/image) */
1689
cea32691 1690 bool enabled;
3787934b 1691 r = proc_cmdline_get_bool("systemd.firstboot", /* flags = */ 0, &enabled);
3ff9fa59
LP
1692 if (r < 0)
1693 return log_error_errno(r, "Failed to parse systemd.firstboot= kernel command line argument, ignoring: %m");
eb650ffe 1694 if (r > 0 && !enabled) {
0a9c4a10 1695 log_debug("Found systemd.firstboot=no kernel command line argument, turning off all prompts.");
aa27bec1 1696 arg_prompt_locale = arg_prompt_keymap = arg_prompt_keymap_auto = arg_prompt_timezone = arg_prompt_hostname = arg_prompt_root_password = arg_prompt_root_shell = false;
eb650ffe 1697 }
3ff9fa59
LP
1698 }
1699
611bb28d
LP
1700 r = mac_init();
1701 if (r < 0)
1702 return r;
1703
6aa05ebd
LP
1704 if (arg_image) {
1705 assert(!arg_root);
1706
1707 r = mount_image_privately_interactively(
1708 arg_image,
84be0c71 1709 arg_image_policy,
4b5de5dd
LP
1710 DISSECT_IMAGE_GENERIC_ROOT |
1711 DISSECT_IMAGE_REQUIRE_ROOT |
1712 DISSECT_IMAGE_VALIDATE_OS |
1713 DISSECT_IMAGE_RELAX_VAR_CHECK |
c65f854a 1714 DISSECT_IMAGE_FSCK |
f4a63ce2
LP
1715 DISSECT_IMAGE_GROWFS |
1716 DISSECT_IMAGE_ALLOW_USERSPACE_VERITY,
a4b3e942 1717 &mounted_dir,
b352e545 1718 &rfd,
e330f97a 1719 &loop_device);
6aa05ebd
LP
1720 if (r < 0)
1721 return r;
1722
a4b3e942 1723 arg_root = strdup(mounted_dir);
6aa05ebd
LP
1724 if (!arg_root)
1725 return log_oom();
b352e545
DDM
1726 } else {
1727 rfd = open(empty_to_root(arg_root), O_DIRECTORY|O_CLOEXEC);
1728 if (rfd < 0)
1729 return log_error_errno(errno, "Failed to open %s: %m", empty_to_root(arg_root));
1730 }
1731
1732 LOG_SET_PREFIX(arg_image ?: arg_root);
73ee723a 1733 DEFER_VOID_CALL(chrome_hide);
b352e545 1734
a0657479
DDM
1735 /* We check these conditions here instead of in parse_argv() so that we can take the root directory
1736 * into account. */
1737
fa350969 1738 if (arg_keymap && !keymap_is_ok(arg_keymap, FD_TO_PTR(rfd)))
321a8c59 1739 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Keymap %s is not installed.", arg_keymap);
fa350969 1740 if (arg_locale && !locale_is_ok(arg_locale, FD_TO_PTR(rfd)))
a0657479 1741 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale);
fa350969 1742 if (arg_locale_messages && !locale_is_ok(arg_locale_messages, FD_TO_PTR(rfd)))
a0657479
DDM
1743 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale_messages);
1744
b352e545
DDM
1745 if (arg_root_shell) {
1746 r = find_shell(rfd, arg_root_shell);
1747 if (r < 0)
1748 return r;
6aa05ebd 1749 }
f582cbca 1750
05eb2c60
DDM
1751 r = process_reset(rfd);
1752 if (r < 0)
1753 return r;
1754
0d2cc656
LP
1755 _cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *mute_console_link = NULL;
1756 r = process_locale(rfd, &mute_console_link);
418b9be5 1757 if (r < 0)
45f39418 1758 return r;
d0c50d8d
ZJS
1759 if (r > 0 && !offline)
1760 (void) reload_system_manager(&bus);
418b9be5 1761
0d2cc656 1762 r = process_keymap(rfd, &mute_console_link);
ed457f13 1763 if (r < 0)
45f39418 1764 return r;
cea32691
ZJS
1765 if (r > 0 && !offline)
1766 (void) reload_vconsole(&bus);
ed457f13 1767
0d2cc656 1768 r = process_timezone(rfd, &mute_console_link);
418b9be5 1769 if (r < 0)
45f39418 1770 return r;
418b9be5 1771
0d2cc656 1772 r = process_hostname(rfd, &mute_console_link);
418b9be5 1773 if (r < 0)
45f39418 1774 return r;
418b9be5 1775
0d2cc656 1776 r = process_root_account(rfd, &mute_console_link);
418b9be5 1777 if (r < 0)
45f39418 1778 return r;
418b9be5 1779
d689dd88 1780 r = process_kernel_cmdline(rfd);
418b9be5 1781 if (r < 0)
45f39418
YW
1782 return r;
1783
d689dd88 1784 r = process_machine_id(rfd);
a5925354
DDM
1785 if (r < 0)
1786 return r;
1787
45f39418 1788 return 0;
418b9be5 1789}
45f39418
YW
1790
1791DEFINE_MAIN_FUNCTION(run);