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