1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <fcntl.h>
4 #include <getopt.h>
5 #include <linux/loop.h>
6 #include <unistd.h>
7 
8 #include "sd-id128.h"
9 
10 #include "alloc-util.h"
11 #include "ask-password-api.h"
12 #include "chase-symlinks.h"
13 #include "copy.h"
14 #include "creds-util.h"
15 #include "dissect-image.h"
16 #include "env-file.h"
17 #include "fd-util.h"
18 #include "fileio.h"
19 #include "fs-util.h"
20 #include "glyph-util.h"
21 #include "hostname-util.h"
22 #include "kbd-util.h"
23 #include "libcrypt-util.h"
24 #include "locale-util.h"
25 #include "main-func.h"
26 #include "memory-util.h"
27 #include "mkdir.h"
28 #include "mount-util.h"
29 #include "os-util.h"
30 #include "parse-argument.h"
31 #include "parse-util.h"
32 #include "path-util.h"
33 #include "pretty-print.h"
34 #include "proc-cmdline.h"
35 #include "pwquality-util.h"
36 #include "random-util.h"
37 #include "smack-util.h"
38 #include "string-util.h"
39 #include "strv.h"
40 #include "terminal-util.h"
41 #include "time-util.h"
42 #include "tmpfile-util-label.h"
43 #include "tmpfile-util.h"
44 #include "umask-util.h"
45 #include "user-util.h"
46 
47 static char *arg_root = NULL;
48 static char *arg_image = NULL;
49 static char *arg_locale = NULL;  /* $LANG */
50 static char *arg_locale_messages = NULL; /* $LC_MESSAGES */
51 static char *arg_keymap = NULL;
52 static char *arg_timezone = NULL;
53 static char *arg_hostname = NULL;
54 static sd_id128_t arg_machine_id = {};
55 static char *arg_root_password = NULL;
56 static char *arg_root_shell = NULL;
57 static char *arg_kernel_cmdline = NULL;
58 static bool arg_prompt_locale = false;
59 static bool arg_prompt_keymap = false;
60 static bool arg_prompt_timezone = false;
61 static bool arg_prompt_hostname = false;
62 static bool arg_prompt_root_password = false;
63 static bool arg_prompt_root_shell = false;
64 static bool arg_copy_locale = false;
65 static bool arg_copy_keymap = false;
66 static bool arg_copy_timezone = false;
67 static bool arg_copy_root_password = false;
68 static bool arg_copy_root_shell = false;
69 static bool arg_force = false;
70 static bool arg_delete_root_password = false;
71 static bool arg_root_password_is_hashed = false;
72 static bool arg_welcome = true;
73 
74 STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
75 STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
76 STATIC_DESTRUCTOR_REGISTER(arg_locale, freep);
77 STATIC_DESTRUCTOR_REGISTER(arg_locale_messages, freep);
78 STATIC_DESTRUCTOR_REGISTER(arg_keymap, freep);
79 STATIC_DESTRUCTOR_REGISTER(arg_timezone, freep);
80 STATIC_DESTRUCTOR_REGISTER(arg_hostname, freep);
81 STATIC_DESTRUCTOR_REGISTER(arg_root_password, erase_and_freep);
82 
press_any_key(void)83 static bool press_any_key(void) {
84         char k = 0;
85         bool need_nl = true;
86 
87         printf("-- Press any key to proceed --");
88         fflush(stdout);
89 
90         (void) read_one_char(stdin, &k, USEC_INFINITY, &need_nl);
91 
92         if (need_nl)
93                 putchar('\n');
94 
95         return k != 'q';
96 }
97 
print_welcome(void)98 static void print_welcome(void) {
99         _cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL;
100         static bool done = false;
101         const char *pn, *ac;
102         int r;
103 
104         if (!arg_welcome)
105                 return;
106 
107         if (done)
108                 return;
109 
110         r = parse_os_release(
111                         arg_root,
112                         "PRETTY_NAME", &pretty_name,
113                         "ANSI_COLOR", &ansi_color);
114         if (r < 0)
115                 log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
116                                "Failed to read os-release file, ignoring: %m");
117 
118         pn = isempty(pretty_name) ? "Linux" : pretty_name;
119         ac = isempty(ansi_color) ? "0" : ansi_color;
120 
121         if (colors_enabled())
122                 printf("\nWelcome to your new installation of \x1B[%sm%s\x1B[0m!\n", ac, pn);
123         else
124                 printf("\nWelcome to your new installation of %s!\n", pn);
125 
126         printf("\nPlease configure your system!\n\n");
127 
128         press_any_key();
129 
130         done = true;
131 }
132 
show_menu(char ** x,unsigned n_columns,unsigned width,unsigned percentage)133 static int show_menu(char **x, unsigned n_columns, unsigned width, unsigned percentage) {
134         unsigned break_lines, break_modulo;
135         size_t n, per_column, i, j;
136 
137         assert(n_columns > 0);
138 
139         n = strv_length(x);
140         per_column = DIV_ROUND_UP(n, n_columns);
141 
142         break_lines = lines();
143         if (break_lines > 2)
144                 break_lines--;
145 
146         /* The first page gets two extra lines, since we want to show
147          * a title */
148         break_modulo = break_lines;
149         if (break_modulo > 3)
150                 break_modulo -= 3;
151 
152         for (i = 0; i < per_column; i++) {
153 
154                 for (j = 0; j < n_columns; j ++) {
155                         _cleanup_free_ char *e = NULL;
156 
157                         if (j * per_column + i >= n)
158                                 break;
159 
160                         e = ellipsize(x[j * per_column + i], width, percentage);
161                         if (!e)
162                                 return log_oom();
163 
164                         printf("%4zu) %-*s", j * per_column + i + 1, width, e);
165                 }
166 
167                 putchar('\n');
168 
169                 /* on the first screen we reserve 2 extra lines for the title */
170                 if (i % break_lines == break_modulo) {
171                         if (!press_any_key())
172                                 return 0;
173                 }
174         }
175 
176         return 0;
177 }
178 
prompt_loop(const char * text,char ** l,unsigned percentage,bool (* is_valid)(const char * name),char ** ret)179 static int prompt_loop(const char *text, char **l, unsigned percentage, bool (*is_valid)(const char *name), char **ret) {
180         int r;
181 
182         assert(text);
183         assert(is_valid);
184         assert(ret);
185 
186         for (;;) {
187                 _cleanup_free_ char *p = NULL;
188                 unsigned u;
189 
190                 r = ask_string(&p, "%s %s (empty to skip, \"list\" to list options): ",
191                                special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET), text);
192                 if (r < 0)
193                         return log_error_errno(r, "Failed to query user: %m");
194 
195                 if (isempty(p)) {
196                         log_warning("No data entered, skipping.");
197                         return 0;
198                 }
199 
200                 if (streq(p, "list")) {
201                         r = show_menu(l, 3, 22, percentage);
202                         if (r < 0)
203                                 return r;
204 
205                         putchar('\n');
206                         continue;
207                 };
208 
209                 r = safe_atou(p, &u);
210                 if (r >= 0) {
211                         if (u <= 0 || u > strv_length(l)) {
212                                 log_error("Specified entry number out of range.");
213                                 continue;
214                         }
215 
216                         log_info("Selected '%s'.", l[u-1]);
217                         return free_and_strdup_warn(ret, l[u-1]);
218                 }
219 
220                 if (!is_valid(p)) {
221                         log_error("Entered data invalid.");
222                         continue;
223                 }
224 
225                 return free_and_replace(*ret, p);
226         }
227 }
228 
locale_is_ok(const char * name)229 static bool locale_is_ok(const char *name) {
230 
231         if (arg_root)
232                 return locale_is_valid(name);
233 
234         return locale_is_installed(name) > 0;
235 }
236 
prompt_locale(void)237 static int prompt_locale(void) {
238         _cleanup_strv_free_ char **locales = NULL;
239         bool acquired_from_creds = false;
240         int r;
241 
242         if (arg_locale || arg_locale_messages)
243                 return 0;
244 
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)
253                 log_debug_errno(r, "Failed to read credential firstboot.locale-message, ignoring: %m");
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 
262         if (!arg_prompt_locale)
263                 return 0;
264 
265         r = get_locales(&locales);
266         if (r < 0)
267                 return log_error_errno(r, "Cannot query locales list: %m");
268 
269         if (strv_isempty(locales))
270                 log_debug("No locales found, skipping locale selection.");
271         else if (strv_length(locales) == 1) {
272 
273                 if (streq(locales[0], SYSTEMD_DEFAULT_LOCALE))
274                         log_debug("Only installed locale is default locale anyway, not setting locale explicitly.");
275                 else {
276                         log_debug("Only a single locale available (%s), selecting it as default.", locales[0]);
277 
278                         arg_locale = strdup(locales[0]);
279                         if (!arg_locale)
280                                 return log_oom();
281 
282                         /* Not setting arg_locale_message here, since it defaults to LANG anyway */
283                 }
284         } else {
285                 print_welcome();
286 
287                 r = prompt_loop("Please enter system locale name or number",
288                                 locales, 60, locale_is_ok, &arg_locale);
289                 if (r < 0)
290                         return r;
291 
292                 if (isempty(arg_locale))
293                         return 0;
294 
295                 r = prompt_loop("Please enter system message locale name or number",
296                                 locales, 60, locale_is_ok, &arg_locale_messages);
297                 if (r < 0)
298                         return r;
299 
300                 /* Suppress the messages setting if it's the same as the main locale anyway */
301                 if (streq_ptr(arg_locale, arg_locale_messages))
302                         arg_locale_messages = mfree(arg_locale_messages);
303         }
304 
305         return 0;
306 }
307 
process_locale(void)308 static int process_locale(void) {
309         const char *etc_localeconf;
310         char* locales[3];
311         unsigned i = 0;
312         int r;
313 
314         etc_localeconf = prefix_roota(arg_root, "/etc/locale.conf");
315         if (laccess(etc_localeconf, F_OK) >= 0 && !arg_force)
316                 return 0;
317 
318         if (arg_copy_locale && arg_root) {
319 
320                 (void) mkdir_parents(etc_localeconf, 0755);
321                 r = copy_file("/etc/locale.conf", etc_localeconf, 0, 0644, 0, 0, COPY_REFLINK);
322                 if (r != -ENOENT) {
323                         if (r < 0)
324                                 return log_error_errno(r, "Failed to copy %s: %m", etc_localeconf);
325 
326                         log_info("%s copied.", etc_localeconf);
327                         return 0;
328                 }
329         }
330 
331         r = prompt_locale();
332         if (r < 0)
333                 return r;
334 
335         if (!isempty(arg_locale))
336                 locales[i++] = strjoina("LANG=", arg_locale);
337         if (!isempty(arg_locale_messages) && !streq(arg_locale_messages, arg_locale))
338                 locales[i++] = strjoina("LC_MESSAGES=", arg_locale_messages);
339 
340         if (i == 0)
341                 return 0;
342 
343         locales[i] = NULL;
344 
345         (void) mkdir_parents(etc_localeconf, 0755);
346         r = write_env_file(etc_localeconf, locales);
347         if (r < 0)
348                 return log_error_errno(r, "Failed to write %s: %m", etc_localeconf);
349 
350         log_info("%s written.", etc_localeconf);
351         return 0;
352 }
353 
prompt_keymap(void)354 static int prompt_keymap(void) {
355         _cleanup_strv_free_ char **kmaps = NULL;
356         int r;
357 
358         if (arg_keymap)
359                 return 0;
360 
361         r = read_credential("firstboot.keymap", (void**) &arg_keymap, NULL);
362         if (r < 0)
363                 log_debug_errno(r, "Failed to read credential firstboot.keymap, ignoring: %m");
364         else {
365                 log_debug("Acquired keymap from credential.");
366                 return 0;
367         }
368 
369         if (!arg_prompt_keymap)
370                 return 0;
371 
372         r = get_keymaps(&kmaps);
373         if (r == -ENOENT) /* no keymaps installed */
374                 return r;
375         if (r < 0)
376                 return log_error_errno(r, "Failed to read keymaps: %m");
377 
378         print_welcome();
379 
380         return prompt_loop("Please enter system keymap name or number",
381                            kmaps, 60, keymap_is_valid, &arg_keymap);
382 }
383 
process_keymap(void)384 static int process_keymap(void) {
385         const char *etc_vconsoleconf;
386         char **keymap;
387         int r;
388 
389         etc_vconsoleconf = prefix_roota(arg_root, "/etc/vconsole.conf");
390         if (laccess(etc_vconsoleconf, F_OK) >= 0 && !arg_force)
391                 return 0;
392 
393         if (arg_copy_keymap && arg_root) {
394 
395                 (void) mkdir_parents(etc_vconsoleconf, 0755);
396                 r = copy_file("/etc/vconsole.conf", etc_vconsoleconf, 0, 0644, 0, 0, COPY_REFLINK);
397                 if (r != -ENOENT) {
398                         if (r < 0)
399                                 return log_error_errno(r, "Failed to copy %s: %m", etc_vconsoleconf);
400 
401                         log_info("%s copied.", etc_vconsoleconf);
402                         return 0;
403                 }
404         }
405 
406         r = prompt_keymap();
407         if (r == -ENOENT)
408                 return 0; /* don't fail if no keymaps are installed */
409         if (r < 0)
410                 return r;
411 
412         if (isempty(arg_keymap))
413                 return 0;
414 
415         keymap = STRV_MAKE(strjoina("KEYMAP=", arg_keymap));
416 
417         r = mkdir_parents(etc_vconsoleconf, 0755);
418         if (r < 0)
419                 return log_error_errno(r, "Failed to create the parent directory of %s: %m", etc_vconsoleconf);
420 
421         r = write_env_file(etc_vconsoleconf, keymap);
422         if (r < 0)
423                 return log_error_errno(r, "Failed to write %s: %m", etc_vconsoleconf);
424 
425         log_info("%s written.", etc_vconsoleconf);
426         return 0;
427 }
428 
timezone_is_valid_log_error(const char * name)429 static bool timezone_is_valid_log_error(const char *name) {
430         return timezone_is_valid(name, LOG_ERR);
431 }
432 
prompt_timezone(void)433 static int prompt_timezone(void) {
434         _cleanup_strv_free_ char **zones = NULL;
435         int r;
436 
437         if (arg_timezone)
438                 return 0;
439 
440         r = read_credential("firstboot.timezone", (void**) &arg_timezone, NULL);
441         if (r < 0)
442                 log_debug_errno(r, "Failed to read credential firstboot.timezone, ignoring: %m");
443         else {
444                 log_debug("Acquired timezone from credential.");
445                 return 0;
446         }
447 
448         if (!arg_prompt_timezone)
449                 return 0;
450 
451         r = get_timezones(&zones);
452         if (r < 0)
453                 return log_error_errno(r, "Cannot query timezone list: %m");
454 
455         print_welcome();
456 
457         r = prompt_loop("Please enter timezone name or number",
458                         zones, 30, timezone_is_valid_log_error, &arg_timezone);
459         if (r < 0)
460                 return r;
461 
462         return 0;
463 }
464 
process_timezone(void)465 static int process_timezone(void) {
466         const char *etc_localtime, *e;
467         int r;
468 
469         etc_localtime = prefix_roota(arg_root, "/etc/localtime");
470         if (laccess(etc_localtime, F_OK) >= 0 && !arg_force)
471                 return 0;
472 
473         if (arg_copy_timezone && arg_root) {
474                 _cleanup_free_ char *p = NULL;
475 
476                 r = readlink_malloc("/etc/localtime", &p);
477                 if (r != -ENOENT) {
478                         if (r < 0)
479                                 return log_error_errno(r, "Failed to read host timezone: %m");
480 
481                         (void) mkdir_parents(etc_localtime, 0755);
482                         if (symlink(p, etc_localtime) < 0)
483                                 return log_error_errno(errno, "Failed to create %s symlink: %m", etc_localtime);
484 
485                         log_info("%s copied.", etc_localtime);
486                         return 0;
487                 }
488         }
489 
490         r = prompt_timezone();
491         if (r < 0)
492                 return r;
493 
494         if (isempty(arg_timezone))
495                 return 0;
496 
497         e = strjoina("../usr/share/zoneinfo/", arg_timezone);
498 
499         (void) mkdir_parents(etc_localtime, 0755);
500         if (symlink(e, etc_localtime) < 0)
501                 return log_error_errno(errno, "Failed to create %s symlink: %m", etc_localtime);
502 
503         log_info("%s written", etc_localtime);
504         return 0;
505 }
506 
prompt_hostname(void)507 static int prompt_hostname(void) {
508         int r;
509 
510         if (arg_hostname)
511                 return 0;
512 
513         if (!arg_prompt_hostname)
514                 return 0;
515 
516         print_welcome();
517         putchar('\n');
518 
519         for (;;) {
520                 _cleanup_free_ char *h = NULL;
521 
522                 r = ask_string(&h, "%s Please enter hostname for new system (empty to skip): ", special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET));
523                 if (r < 0)
524                         return log_error_errno(r, "Failed to query hostname: %m");
525 
526                 if (isempty(h)) {
527                         log_warning("No hostname entered, skipping.");
528                         break;
529                 }
530 
531                 if (!hostname_is_valid(h, VALID_HOSTNAME_TRAILING_DOT)) {
532                         log_error("Specified hostname invalid.");
533                         continue;
534                 }
535 
536                 /* Get rid of the trailing dot that we allow, but don't want to see */
537                 arg_hostname = hostname_cleanup(h);
538                 h = NULL;
539                 break;
540         }
541 
542         return 0;
543 }
544 
process_hostname(void)545 static int process_hostname(void) {
546         const char *etc_hostname;
547         int r;
548 
549         etc_hostname = prefix_roota(arg_root, "/etc/hostname");
550         if (laccess(etc_hostname, F_OK) >= 0 && !arg_force)
551                 return 0;
552 
553         r = prompt_hostname();
554         if (r < 0)
555                 return r;
556 
557         if (isempty(arg_hostname))
558                 return 0;
559 
560         r = write_string_file(etc_hostname, arg_hostname,
561                               WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_SYNC | WRITE_STRING_FILE_MKDIR_0755 |
562                               (arg_force ? WRITE_STRING_FILE_ATOMIC : 0));
563         if (r < 0)
564                 return log_error_errno(r, "Failed to write %s: %m", etc_hostname);
565 
566         log_info("%s written.", etc_hostname);
567         return 0;
568 }
569 
process_machine_id(void)570 static int process_machine_id(void) {
571         const char *etc_machine_id;
572         int r;
573 
574         etc_machine_id = prefix_roota(arg_root, "/etc/machine-id");
575         if (laccess(etc_machine_id, F_OK) >= 0 && !arg_force)
576                 return 0;
577 
578         if (sd_id128_is_null(arg_machine_id))
579                 return 0;
580 
581         r = write_string_file(etc_machine_id, SD_ID128_TO_STRING(arg_machine_id),
582                               WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_SYNC | WRITE_STRING_FILE_MKDIR_0755 |
583                               (arg_force ? WRITE_STRING_FILE_ATOMIC : 0));
584         if (r < 0)
585                 return log_error_errno(r, "Failed to write machine id: %m");
586 
587         log_info("%s written.", etc_machine_id);
588         return 0;
589 }
590 
prompt_root_password(void)591 static int prompt_root_password(void) {
592         const char *msg1, *msg2;
593         int r;
594 
595         if (arg_root_password)
596                 return 0;
597 
598         r = read_credential("passwd.hashed-password.root", (void**) &arg_root_password, NULL);
599         if (r == -ENOENT) {
600                 r = read_credential("passwd.plaintext-password.root", (void**) &arg_root_password, NULL);
601                 if (r < 0)
602                         log_debug_errno(r, "Couldn't read credential 'passwd.{hashed|plaintext}-password.root', ignoring: %m");
603                 else {
604                         arg_root_password_is_hashed = false;
605                         return 0;
606                 }
607         } else if (r < 0)
608                 log_debug_errno(r, "Couldn't read credential 'passwd.hashed-password.root', ignoring: %m");
609         else {
610                 arg_root_password_is_hashed = true;
611                 return 0;
612         }
613 
614         if (!arg_prompt_root_password)
615                 return 0;
616 
617         print_welcome();
618         putchar('\n');
619 
620         msg1 = strjoina(special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET), " Please enter a new root password (empty to skip):");
621         msg2 = strjoina(special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET), " Please enter new root password again:");
622 
623         suggest_passwords();
624 
625         for (;;) {
626                 _cleanup_strv_free_erase_ char **a = NULL, **b = NULL;
627                 _cleanup_free_ char *error = NULL;
628 
629                 r = ask_password_tty(-1, msg1, NULL, 0, 0, NULL, &a);
630                 if (r < 0)
631                         return log_error_errno(r, "Failed to query root password: %m");
632                 if (strv_length(a) != 1)
633                         return log_error_errno(SYNTHETIC_ERRNO(EIO),
634                                                "Received multiple passwords, where we expected one.");
635 
636                 if (isempty(*a)) {
637                         log_warning("No password entered, skipping.");
638                         break;
639                 }
640 
641                 r = quality_check_password(*a, "root", &error);
642                 if (r < 0)
643                         return log_error_errno(r, "Failed to check quality of password: %m");
644                 if (r == 0)
645                         log_warning("Password is weak, accepting anyway: %s", error);
646 
647                 r = ask_password_tty(-1, msg2, NULL, 0, 0, NULL, &b);
648                 if (r < 0)
649                         return log_error_errno(r, "Failed to query root password: %m");
650                 if (strv_length(b) != 1)
651                         return log_error_errno(SYNTHETIC_ERRNO(EIO),
652                                                "Received multiple passwords, where we expected one.");
653 
654                 if (!streq(*a, *b)) {
655                         log_error("Entered passwords did not match, please try again.");
656                         continue;
657                 }
658 
659                 arg_root_password = TAKE_PTR(*a);
660                 break;
661         }
662 
663         return 0;
664 }
665 
find_shell(const char * path,const char * root)666 static int find_shell(const char *path, const char *root) {
667         int r;
668 
669         assert(path);
670 
671         if (!valid_shell(path))
672                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "%s is not a valid shell", path);
673 
674         r = chase_symlinks(path, root, CHASE_PREFIX_ROOT, NULL, NULL);
675         if (r < 0) {
676                 const char *p;
677                 p = prefix_roota(root, path);
678                 return log_error_errno(r, "Failed to resolve shell %s: %m", p);
679         }
680 
681         return 0;
682 }
683 
prompt_root_shell(void)684 static int prompt_root_shell(void) {
685         int r;
686 
687         if (arg_root_shell)
688                 return 0;
689 
690         r = read_credential("passwd.shell.root", (void**) &arg_root_shell, NULL);
691         if (r < 0)
692                 log_debug_errno(r, "Failed to read credential passwd.shell.root, ignoring: %m");
693         else {
694                 log_debug("Acquired root shell from credential.");
695                 return 0;
696         }
697 
698         if (!arg_prompt_root_shell)
699                 return 0;
700 
701         print_welcome();
702         putchar('\n');
703 
704         for (;;) {
705                 _cleanup_free_ char *s = NULL;
706 
707                 r = ask_string(&s, "%s Please enter root shell for new system (empty to skip): ", special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET));
708                 if (r < 0)
709                         return log_error_errno(r, "Failed to query root shell: %m");
710 
711                 if (isempty(s)) {
712                         log_warning("No shell entered, skipping.");
713                         break;
714                 }
715 
716                 r = find_shell(s, arg_root);
717                 if (r < 0)
718                         continue;
719 
720                 arg_root_shell = TAKE_PTR(s);
721                 break;
722         }
723 
724         return 0;
725 }
726 
write_root_passwd(const char * passwd_path,const char * password,const char * shell)727 static int write_root_passwd(const char *passwd_path, const char *password, const char *shell) {
728         _cleanup_fclose_ FILE *original = NULL, *passwd = NULL;
729         _cleanup_(unlink_and_freep) char *passwd_tmp = NULL;
730         int r;
731 
732         assert(password);
733 
734         r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp);
735         if (r < 0)
736                 return r;
737 
738         original = fopen(passwd_path, "re");
739         if (original) {
740                 struct passwd *i;
741 
742                 r = copy_rights(fileno(original), fileno(passwd));
743                 if (r < 0)
744                         return r;
745 
746                 while ((r = fgetpwent_sane(original, &i)) > 0) {
747 
748                         if (streq(i->pw_name, "root")) {
749                                 i->pw_passwd = (char *) password;
750                                 if (shell)
751                                         i->pw_shell = (char *) shell;
752                         }
753 
754                         r = putpwent_sane(i, passwd);
755                         if (r < 0)
756                                 return r;
757                 }
758                 if (r < 0)
759                         return r;
760 
761         } else {
762                 struct passwd root = {
763                         .pw_name = (char *) "root",
764                         .pw_passwd = (char *) password,
765                         .pw_uid = 0,
766                         .pw_gid = 0,
767                         .pw_gecos = (char *) "Super User",
768                         .pw_dir = (char *) "/root",
769                         .pw_shell = (char *) (shell ?: "/bin/sh"),
770                 };
771 
772                 if (errno != ENOENT)
773                         return -errno;
774 
775                 r = fchmod(fileno(passwd), 0644);
776                 if (r < 0)
777                         return -errno;
778 
779                 r = putpwent_sane(&root, passwd);
780                 if (r < 0)
781                         return r;
782         }
783 
784         r = fflush_sync_and_check(passwd);
785         if (r < 0)
786                 return r;
787 
788         r = rename_and_apply_smack_floor_label(passwd_tmp, passwd_path);
789         if (r < 0)
790                 return r;
791 
792         return 0;
793 }
794 
write_root_shadow(const char * shadow_path,const char * hashed_password)795 static int write_root_shadow(const char *shadow_path, const char *hashed_password) {
796         _cleanup_fclose_ FILE *original = NULL, *shadow = NULL;
797         _cleanup_(unlink_and_freep) char *shadow_tmp = NULL;
798         int r;
799 
800         assert(hashed_password);
801 
802         r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp);
803         if (r < 0)
804                 return r;
805 
806         original = fopen(shadow_path, "re");
807         if (original) {
808                 struct spwd *i;
809 
810                 r = copy_rights(fileno(original), fileno(shadow));
811                 if (r < 0)
812                         return r;
813 
814                 while ((r = fgetspent_sane(original, &i)) > 0) {
815 
816                         if (streq(i->sp_namp, "root")) {
817                                 i->sp_pwdp = (char *) hashed_password;
818                                 i->sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
819                         }
820 
821                         r = putspent_sane(i, shadow);
822                         if (r < 0)
823                                 return r;
824                 }
825                 if (r < 0)
826                         return r;
827 
828         } else {
829                 struct spwd root = {
830                         .sp_namp = (char*) "root",
831                         .sp_pwdp = (char *) hashed_password,
832                         .sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY),
833                         .sp_min = -1,
834                         .sp_max = -1,
835                         .sp_warn = -1,
836                         .sp_inact = -1,
837                         .sp_expire = -1,
838                         .sp_flag = ULONG_MAX, /* this appears to be what everybody does ... */
839                 };
840 
841                 if (errno != ENOENT)
842                         return -errno;
843 
844                 r = fchmod(fileno(shadow), 0000);
845                 if (r < 0)
846                         return -errno;
847 
848                 r = putspent_sane(&root, shadow);
849                 if (r < 0)
850                         return r;
851         }
852 
853         r = fflush_sync_and_check(shadow);
854         if (r < 0)
855                 return r;
856 
857         r = rename_and_apply_smack_floor_label(shadow_tmp, shadow_path);
858         if (r < 0)
859                 return r;
860 
861         return 0;
862 }
863 
process_root_args(void)864 static int process_root_args(void) {
865         _cleanup_close_ int lock = -1;
866         _cleanup_(erase_and_freep) char *_hashed_password = NULL;
867         const char *password, *hashed_password;
868         const char *etc_passwd, *etc_shadow;
869         int r;
870 
871         etc_passwd = prefix_roota(arg_root, "/etc/passwd");
872         etc_shadow = prefix_roota(arg_root, "/etc/shadow");
873 
874         /* We only mess with passwd and shadow if both do not exist or --force is specified. These files are
875          * tightly coupled and hence we make sure we have permission from the user to create/modify both
876          * files. */
877         if ((laccess(etc_passwd, F_OK) >= 0 || laccess(etc_shadow, F_OK) >= 0) && !arg_force)
878                 return 0;
879         /* Don't create/modify passwd and shadow if not asked */
880         if (!(arg_root_password || arg_prompt_root_password || arg_copy_root_password || arg_delete_root_password ||
881               arg_root_shell || arg_prompt_root_shell || arg_copy_root_shell))
882                 return 0;
883 
884         (void) mkdir_parents(etc_passwd, 0755);
885 
886         lock = take_etc_passwd_lock(arg_root);
887         if (lock < 0)
888                 return log_error_errno(lock, "Failed to take a lock on %s: %m", etc_passwd);
889 
890         if (arg_copy_root_shell && arg_root) {
891                 struct passwd *p;
892 
893                 errno = 0;
894                 p = getpwnam("root");
895                 if (!p)
896                         return log_error_errno(errno_or_else(EIO), "Failed to find passwd entry for root: %m");
897 
898                 r = free_and_strdup(&arg_root_shell, p->pw_shell);
899                 if (r < 0)
900                         return log_oom();
901         }
902 
903         r = prompt_root_shell();
904         if (r < 0)
905                 return r;
906 
907         if (arg_copy_root_password && arg_root) {
908                 struct spwd *p;
909 
910                 errno = 0;
911                 p = getspnam("root");
912                 if (!p)
913                         return log_error_errno(errno_or_else(EIO), "Failed to find shadow entry for root: %m");
914 
915                 r = free_and_strdup(&arg_root_password, p->sp_pwdp);
916                 if (r < 0)
917                         return log_oom();
918 
919                 arg_root_password_is_hashed = true;
920         }
921 
922         r = prompt_root_password();
923         if (r < 0)
924                 return r;
925 
926         if (arg_root_password && arg_root_password_is_hashed) {
927                 password = PASSWORD_SEE_SHADOW;
928                 hashed_password = arg_root_password;
929         } else if (arg_root_password) {
930                 r = hash_password(arg_root_password, &_hashed_password);
931                 if (r < 0)
932                         return log_error_errno(r, "Failed to hash password: %m");
933 
934                 password = PASSWORD_SEE_SHADOW;
935                 hashed_password = _hashed_password;
936 
937         } else if (arg_delete_root_password)
938                 password = hashed_password = PASSWORD_NONE;
939         else
940                 password = hashed_password = PASSWORD_LOCKED_AND_INVALID;
941 
942         r = write_root_passwd(etc_passwd, password, arg_root_shell);
943         if (r < 0)
944                 return log_error_errno(r, "Failed to write %s: %m", etc_passwd);
945 
946         log_info("%s written", etc_passwd);
947 
948         r = write_root_shadow(etc_shadow, hashed_password);
949         if (r < 0)
950                 return log_error_errno(r, "Failed to write %s: %m", etc_shadow);
951 
952         log_info("%s written.", etc_shadow);
953         return 0;
954 }
955 
process_kernel_cmdline(void)956 static int process_kernel_cmdline(void) {
957         const char *etc_kernel_cmdline;
958         int r;
959 
960         etc_kernel_cmdline = prefix_roota(arg_root, "/etc/kernel/cmdline");
961         if (laccess(etc_kernel_cmdline, F_OK) >= 0 && !arg_force)
962                 return 0;
963 
964         if (!arg_kernel_cmdline)
965                 return 0;
966 
967         r = write_string_file(etc_kernel_cmdline, arg_kernel_cmdline,
968                               WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_SYNC | WRITE_STRING_FILE_MKDIR_0755 |
969                               (arg_force ? WRITE_STRING_FILE_ATOMIC : 0));
970         if (r < 0)
971                 return log_error_errno(r, "Failed to write %s: %m", etc_kernel_cmdline);
972 
973         log_info("%s written.", etc_kernel_cmdline);
974         return 0;
975 }
976 
help(void)977 static int help(void) {
978         _cleanup_free_ char *link = NULL;
979         int r;
980 
981         r = terminal_urlify_man("systemd-firstboot", "1", &link);
982         if (r < 0)
983                 return log_oom();
984 
985         printf("%s [OPTIONS...]\n\n"
986                "Configures basic settings of the system.\n\n"
987                "  -h --help                       Show this help\n"
988                "     --version                    Show package version\n"
989                "     --root=PATH                  Operate on an alternate filesystem root\n"
990                "     --image=PATH                 Operate on an alternate filesystem image\n"
991                "     --locale=LOCALE              Set primary locale (LANG=)\n"
992                "     --locale-messages=LOCALE     Set message locale (LC_MESSAGES=)\n"
993                "     --keymap=KEYMAP              Set keymap\n"
994                "     --timezone=TIMEZONE          Set timezone\n"
995                "     --hostname=NAME              Set hostname\n"
996                "     --machine-ID=ID              Set machine ID\n"
997                "     --root-password=PASSWORD     Set root password from plaintext password\n"
998                "     --root-password-file=FILE    Set root password from file\n"
999                "     --root-password-hashed=HASH  Set root password from hashed password\n"
1000                "     --root-shell=SHELL           Set root shell\n"
1001                "     --prompt-locale              Prompt the user for locale settings\n"
1002                "     --prompt-keymap              Prompt the user for keymap settings\n"
1003                "     --prompt-timezone            Prompt the user for timezone\n"
1004                "     --prompt-hostname            Prompt the user for hostname\n"
1005                "     --prompt-root-password       Prompt the user for root password\n"
1006                "     --prompt-root-shell          Prompt the user for root shell\n"
1007                "     --prompt                     Prompt for all of the above\n"
1008                "     --copy-locale                Copy locale from host\n"
1009                "     --copy-keymap                Copy keymap from host\n"
1010                "     --copy-timezone              Copy timezone from host\n"
1011                "     --copy-root-password         Copy root password from host\n"
1012                "     --copy-root-shell            Copy root shell from host\n"
1013                "     --copy                       Copy locale, keymap, timezone, root password\n"
1014                "     --setup-machine-id           Generate a new random machine ID\n"
1015                "     --force                      Overwrite existing files\n"
1016                "     --delete-root-password       Delete root password\n"
1017                "     --welcome=no                 Disable the welcome text\n"
1018                "\nSee the %s for details.\n",
1019                program_invocation_short_name,
1020                link);
1021 
1022         return 0;
1023 }
1024 
parse_argv(int argc,char * argv[])1025 static int parse_argv(int argc, char *argv[]) {
1026 
1027         enum {
1028                 ARG_VERSION = 0x100,
1029                 ARG_ROOT,
1030                 ARG_IMAGE,
1031                 ARG_LOCALE,
1032                 ARG_LOCALE_MESSAGES,
1033                 ARG_KEYMAP,
1034                 ARG_TIMEZONE,
1035                 ARG_HOSTNAME,
1036                 ARG_MACHINE_ID,
1037                 ARG_ROOT_PASSWORD,
1038                 ARG_ROOT_PASSWORD_FILE,
1039                 ARG_ROOT_PASSWORD_HASHED,
1040                 ARG_ROOT_SHELL,
1041                 ARG_KERNEL_COMMAND_LINE,
1042                 ARG_PROMPT,
1043                 ARG_PROMPT_LOCALE,
1044                 ARG_PROMPT_KEYMAP,
1045                 ARG_PROMPT_TIMEZONE,
1046                 ARG_PROMPT_HOSTNAME,
1047                 ARG_PROMPT_ROOT_PASSWORD,
1048                 ARG_PROMPT_ROOT_SHELL,
1049                 ARG_COPY,
1050                 ARG_COPY_LOCALE,
1051                 ARG_COPY_KEYMAP,
1052                 ARG_COPY_TIMEZONE,
1053                 ARG_COPY_ROOT_PASSWORD,
1054                 ARG_COPY_ROOT_SHELL,
1055                 ARG_SETUP_MACHINE_ID,
1056                 ARG_FORCE,
1057                 ARG_DELETE_ROOT_PASSWORD,
1058                 ARG_WELCOME,
1059         };
1060 
1061         static const struct option options[] = {
1062                 { "help",                    no_argument,       NULL, 'h'                         },
1063                 { "version",                 no_argument,       NULL, ARG_VERSION                 },
1064                 { "root",                    required_argument, NULL, ARG_ROOT                    },
1065                 { "image",                   required_argument, NULL, ARG_IMAGE                   },
1066                 { "locale",                  required_argument, NULL, ARG_LOCALE                  },
1067                 { "locale-messages",         required_argument, NULL, ARG_LOCALE_MESSAGES         },
1068                 { "keymap",                  required_argument, NULL, ARG_KEYMAP                  },
1069                 { "timezone",                required_argument, NULL, ARG_TIMEZONE                },
1070                 { "hostname",                required_argument, NULL, ARG_HOSTNAME                },
1071                 { "machine-id",              required_argument, NULL, ARG_MACHINE_ID              },
1072                 { "root-password",           required_argument, NULL, ARG_ROOT_PASSWORD           },
1073                 { "root-password-file",      required_argument, NULL, ARG_ROOT_PASSWORD_FILE      },
1074                 { "root-password-hashed",    required_argument, NULL, ARG_ROOT_PASSWORD_HASHED    },
1075                 { "root-shell",              required_argument, NULL, ARG_ROOT_SHELL              },
1076                 { "kernel-command-line",     required_argument, NULL, ARG_KERNEL_COMMAND_LINE     },
1077                 { "prompt",                  no_argument,       NULL, ARG_PROMPT                  },
1078                 { "prompt-locale",           no_argument,       NULL, ARG_PROMPT_LOCALE           },
1079                 { "prompt-keymap",           no_argument,       NULL, ARG_PROMPT_KEYMAP           },
1080                 { "prompt-timezone",         no_argument,       NULL, ARG_PROMPT_TIMEZONE         },
1081                 { "prompt-hostname",         no_argument,       NULL, ARG_PROMPT_HOSTNAME         },
1082                 { "prompt-root-password",    no_argument,       NULL, ARG_PROMPT_ROOT_PASSWORD    },
1083                 { "prompt-root-shell",       no_argument,       NULL, ARG_PROMPT_ROOT_SHELL       },
1084                 { "copy",                    no_argument,       NULL, ARG_COPY                    },
1085                 { "copy-locale",             no_argument,       NULL, ARG_COPY_LOCALE             },
1086                 { "copy-keymap",             no_argument,       NULL, ARG_COPY_KEYMAP             },
1087                 { "copy-timezone",           no_argument,       NULL, ARG_COPY_TIMEZONE           },
1088                 { "copy-root-password",      no_argument,       NULL, ARG_COPY_ROOT_PASSWORD      },
1089                 { "copy-root-shell",         no_argument,       NULL, ARG_COPY_ROOT_SHELL         },
1090                 { "setup-machine-id",        no_argument,       NULL, ARG_SETUP_MACHINE_ID        },
1091                 { "force",                   no_argument,       NULL, ARG_FORCE                   },
1092                 { "delete-root-password",    no_argument,       NULL, ARG_DELETE_ROOT_PASSWORD    },
1093                 { "welcome",                 required_argument, NULL, ARG_WELCOME                 },
1094                 {}
1095         };
1096 
1097         int r, c;
1098 
1099         assert(argc >= 0);
1100         assert(argv);
1101 
1102         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1103 
1104                 switch (c) {
1105 
1106                 case 'h':
1107                         return help();
1108 
1109                 case ARG_VERSION:
1110                         return version();
1111 
1112                 case ARG_ROOT:
1113                         r = parse_path_argument(optarg, true, &arg_root);
1114                         if (r < 0)
1115                                 return r;
1116                         break;
1117 
1118                 case ARG_IMAGE:
1119                         r = parse_path_argument(optarg, false, &arg_image);
1120                         if (r < 0)
1121                                 return r;
1122                         break;
1123 
1124                 case ARG_LOCALE:
1125                         r = free_and_strdup(&arg_locale, optarg);
1126                         if (r < 0)
1127                                 return log_oom();
1128 
1129                         break;
1130 
1131                 case ARG_LOCALE_MESSAGES:
1132                         r = free_and_strdup(&arg_locale_messages, optarg);
1133                         if (r < 0)
1134                                 return log_oom();
1135 
1136                         break;
1137 
1138                 case ARG_KEYMAP:
1139                         if (!keymap_is_valid(optarg))
1140                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1141                                                        "Keymap %s is not valid.", optarg);
1142 
1143                         r = free_and_strdup(&arg_keymap, optarg);
1144                         if (r < 0)
1145                                 return log_oom();
1146 
1147                         break;
1148 
1149                 case ARG_TIMEZONE:
1150                         if (!timezone_is_valid(optarg, LOG_ERR))
1151                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1152                                                        "Timezone %s is not valid.", optarg);
1153 
1154                         r = free_and_strdup(&arg_timezone, optarg);
1155                         if (r < 0)
1156                                 return log_oom();
1157 
1158                         break;
1159 
1160                 case ARG_ROOT_PASSWORD:
1161                         r = free_and_strdup(&arg_root_password, optarg);
1162                         if (r < 0)
1163                                 return log_oom();
1164 
1165                         arg_root_password_is_hashed = false;
1166                         break;
1167 
1168                 case ARG_ROOT_PASSWORD_FILE:
1169                         arg_root_password = mfree(arg_root_password);
1170 
1171                         r = read_one_line_file(optarg, &arg_root_password);
1172                         if (r < 0)
1173                                 return log_error_errno(r, "Failed to read %s: %m", optarg);
1174 
1175                         arg_root_password_is_hashed = false;
1176                         break;
1177 
1178                 case ARG_ROOT_PASSWORD_HASHED:
1179                         r = free_and_strdup(&arg_root_password, optarg);
1180                         if (r < 0)
1181                                 return log_oom();
1182 
1183                         arg_root_password_is_hashed = true;
1184                         break;
1185 
1186                 case ARG_ROOT_SHELL:
1187                         r = find_shell(optarg, arg_root);
1188                         if (r < 0)
1189                                 return r;
1190 
1191                         r = free_and_strdup(&arg_root_shell, optarg);
1192                         if (r < 0)
1193                                 return log_oom();
1194 
1195                         break;
1196 
1197                 case ARG_HOSTNAME:
1198                         if (!hostname_is_valid(optarg, VALID_HOSTNAME_TRAILING_DOT))
1199                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1200                                                        "Host name %s is not valid.", optarg);
1201 
1202                         r = free_and_strdup(&arg_hostname, optarg);
1203                         if (r < 0)
1204                                 return log_oom();
1205 
1206                         hostname_cleanup(arg_hostname);
1207                         break;
1208 
1209                 case ARG_MACHINE_ID:
1210                         r = sd_id128_from_string(optarg, &arg_machine_id);
1211                         if (r < 0)
1212                                 return log_error_errno(r, "Failed to parse machine id %s.", optarg);
1213 
1214                         break;
1215 
1216                 case ARG_KERNEL_COMMAND_LINE:
1217                         r = free_and_strdup(&arg_kernel_cmdline, optarg);
1218                         if (r < 0)
1219                                 return log_oom();
1220 
1221                         break;
1222 
1223                 case ARG_PROMPT:
1224                         arg_prompt_locale = arg_prompt_keymap = arg_prompt_timezone = arg_prompt_hostname =
1225                                 arg_prompt_root_password = arg_prompt_root_shell = true;
1226                         break;
1227 
1228                 case ARG_PROMPT_LOCALE:
1229                         arg_prompt_locale = true;
1230                         break;
1231 
1232                 case ARG_PROMPT_KEYMAP:
1233                         arg_prompt_keymap = true;
1234                         break;
1235 
1236                 case ARG_PROMPT_TIMEZONE:
1237                         arg_prompt_timezone = true;
1238                         break;
1239 
1240                 case ARG_PROMPT_HOSTNAME:
1241                         arg_prompt_hostname = true;
1242                         break;
1243 
1244                 case ARG_PROMPT_ROOT_PASSWORD:
1245                         arg_prompt_root_password = true;
1246                         break;
1247 
1248                 case ARG_PROMPT_ROOT_SHELL:
1249                         arg_prompt_root_shell = true;
1250                         break;
1251 
1252                 case ARG_COPY:
1253                         arg_copy_locale = arg_copy_keymap = arg_copy_timezone = arg_copy_root_password =
1254                                 arg_copy_root_shell = true;
1255                         break;
1256 
1257                 case ARG_COPY_LOCALE:
1258                         arg_copy_locale = true;
1259                         break;
1260 
1261                 case ARG_COPY_KEYMAP:
1262                         arg_copy_keymap = true;
1263                         break;
1264 
1265                 case ARG_COPY_TIMEZONE:
1266                         arg_copy_timezone = true;
1267                         break;
1268 
1269                 case ARG_COPY_ROOT_PASSWORD:
1270                         arg_copy_root_password = true;
1271                         break;
1272 
1273                 case ARG_COPY_ROOT_SHELL:
1274                         arg_copy_root_shell = true;
1275                         break;
1276 
1277                 case ARG_SETUP_MACHINE_ID:
1278                         r = sd_id128_randomize(&arg_machine_id);
1279                         if (r < 0)
1280                                 return log_error_errno(r, "Failed to generate randomized machine ID: %m");
1281 
1282                         break;
1283 
1284                 case ARG_FORCE:
1285                         arg_force = true;
1286                         break;
1287 
1288                 case ARG_DELETE_ROOT_PASSWORD:
1289                         arg_delete_root_password = true;
1290                         break;
1291 
1292                 case ARG_WELCOME:
1293                         r = parse_boolean(optarg);
1294                         if (r < 0)
1295                                 return log_error_errno(r, "Failed to parse --welcome= argument: %s", optarg);
1296 
1297                         arg_welcome = r;
1298                         break;
1299 
1300                 case '?':
1301                         return -EINVAL;
1302 
1303                 default:
1304                         assert_not_reached();
1305                 }
1306 
1307         /* We check if the specified locale strings are valid down here, so that we can take --root= into
1308          * account when looking for the locale files. */
1309 
1310         if (arg_locale && !locale_is_ok(arg_locale))
1311                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale);
1312         if (arg_locale_messages && !locale_is_ok(arg_locale_messages))
1313                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale_messages);
1314 
1315         if (arg_delete_root_password && (arg_copy_root_password || arg_root_password || arg_prompt_root_password))
1316                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1317                                        "--delete-root-password cannot be combined with other root password options");
1318 
1319         if (arg_image && arg_root)
1320                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Please specify either --root= or --image=, the combination of both is not supported.");
1321 
1322         return 1;
1323 }
1324 
run(int argc,char * argv[])1325 static int run(int argc, char *argv[]) {
1326         _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
1327         _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
1328         _cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
1329         int r;
1330 
1331         r = parse_argv(argc, argv);
1332         if (r <= 0)
1333                 return r;
1334 
1335         log_setup();
1336 
1337         umask(0022);
1338 
1339         if (!arg_root && !arg_image) {
1340                 bool enabled;
1341 
1342                 /* If we are called without --root=/--image= let's honour the systemd.firstboot kernel
1343                  * command line option, because we are called to provision the host with basic settings (as
1344                  * opposed to some other file system tree/image) */
1345 
1346                 r = proc_cmdline_get_bool("systemd.firstboot", &enabled);
1347                 if (r < 0)
1348                         return log_error_errno(r, "Failed to parse systemd.firstboot= kernel command line argument, ignoring: %m");
1349                 if (r > 0 && !enabled)
1350                         return 0; /* disabled */
1351         }
1352 
1353         if (arg_image) {
1354                 assert(!arg_root);
1355 
1356                 r = mount_image_privately_interactively(
1357                                 arg_image,
1358                                 DISSECT_IMAGE_GENERIC_ROOT |
1359                                 DISSECT_IMAGE_REQUIRE_ROOT |
1360                                 DISSECT_IMAGE_VALIDATE_OS |
1361                                 DISSECT_IMAGE_RELAX_VAR_CHECK |
1362                                 DISSECT_IMAGE_FSCK |
1363                                 DISSECT_IMAGE_GROWFS,
1364                                 &unlink_dir,
1365                                 &loop_device,
1366                                 &decrypted_image);
1367                 if (r < 0)
1368                         return r;
1369 
1370                 arg_root = strdup(unlink_dir);
1371                 if (!arg_root)
1372                         return log_oom();
1373         }
1374 
1375         r = process_locale();
1376         if (r < 0)
1377                 return r;
1378 
1379         r = process_keymap();
1380         if (r < 0)
1381                 return r;
1382 
1383         r = process_timezone();
1384         if (r < 0)
1385                 return r;
1386 
1387         r = process_hostname();
1388         if (r < 0)
1389                 return r;
1390 
1391         r = process_machine_id();
1392         if (r < 0)
1393                 return r;
1394 
1395         r = process_root_args();
1396         if (r < 0)
1397                 return r;
1398 
1399         r = process_kernel_cmdline();
1400         if (r < 0)
1401                 return r;
1402 
1403         return 0;
1404 }
1405 
1406 DEFINE_MAIN_FUNCTION(run);
1407