]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/fstab-generator/fstab-generator.c
Merge pull request #5283 from poettering/tighten-sandbox
[thirdparty/systemd.git] / src / fstab-generator / fstab-generator.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2012 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <errno.h>
21 #include <mntent.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include "alloc-util.h"
27 #include "fd-util.h"
28 #include "fileio.h"
29 #include "fstab-util.h"
30 #include "generator.h"
31 #include "log.h"
32 #include "mkdir.h"
33 #include "mount-setup.h"
34 #include "mount-util.h"
35 #include "parse-util.h"
36 #include "path-util.h"
37 #include "proc-cmdline.h"
38 #include "special.h"
39 #include "stat-util.h"
40 #include "string-util.h"
41 #include "strv.h"
42 #include "unit-name.h"
43 #include "util.h"
44 #include "virt.h"
45 #include "volatile-util.h"
46
47 static const char *arg_dest = "/tmp";
48 static const char *arg_dest_late = "/tmp";
49 static bool arg_fstab_enabled = true;
50 static char *arg_root_what = NULL;
51 static char *arg_root_fstype = NULL;
52 static char *arg_root_options = NULL;
53 static char *arg_root_hash = NULL;
54 static int arg_root_rw = -1;
55 static char *arg_usr_what = NULL;
56 static char *arg_usr_fstype = NULL;
57 static char *arg_usr_options = NULL;
58 static VolatileMode arg_volatile_mode = _VOLATILE_MODE_INVALID;
59
60 static int write_options(FILE *f, const char *options) {
61 _cleanup_free_ char *o = NULL;
62
63 if (isempty(options))
64 return 0;
65
66 if (streq(options, "defaults"))
67 return 0;
68
69 o = strreplace(options, "%", "%%");
70 if (!o)
71 return log_oom();
72
73 fprintf(f, "Options=%s\n", o);
74 return 1;
75 }
76
77 static int write_what(FILE *f, const char *what) {
78 _cleanup_free_ char *w = NULL;
79
80 w = strreplace(what, "%", "%%");
81 if (!w)
82 return log_oom();
83
84 fprintf(f, "What=%s\n", w);
85 return 1;
86 }
87
88 static int add_swap(
89 const char *what,
90 struct mntent *me,
91 bool noauto,
92 bool nofail) {
93
94 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
95 _cleanup_fclose_ FILE *f = NULL;
96 int r;
97
98 assert(what);
99 assert(me);
100
101 if (access("/proc/swaps", F_OK) < 0) {
102 log_info("Swap not supported, ignoring fstab swap entry for %s.", what);
103 return 0;
104 }
105
106 if (detect_container() > 0) {
107 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
108 return 0;
109 }
110
111 r = unit_name_from_path(what, ".swap", &name);
112 if (r < 0)
113 return log_error_errno(r, "Failed to generate unit name: %m");
114
115 unit = strjoin(arg_dest, "/", name);
116 if (!unit)
117 return log_oom();
118
119 f = fopen(unit, "wxe");
120 if (!f)
121 return log_error_errno(errno,
122 errno == EEXIST ?
123 "Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?" :
124 "Failed to create unit file %s: %m",
125 unit);
126
127 fputs("# Automatically generated by systemd-fstab-generator\n\n"
128 "[Unit]\n"
129 "SourcePath=/etc/fstab\n"
130 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
131 "[Swap]\n", f);
132
133 r = write_what(f, what);
134 if (r < 0)
135 return r;
136
137 r = write_options(f, me->mnt_opts);
138 if (r < 0)
139 return r;
140
141 r = fflush_and_check(f);
142 if (r < 0)
143 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
144
145 /* use what as where, to have a nicer error message */
146 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
147 if (r < 0)
148 return r;
149
150 if (!noauto) {
151 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET,
152 nofail ? ".wants/" : ".requires/", name, NULL);
153 if (!lnk)
154 return log_oom();
155
156 mkdir_parents_label(lnk, 0755);
157 if (symlink(unit, lnk) < 0)
158 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
159 }
160
161 return 0;
162 }
163
164 static bool mount_is_network(struct mntent *me) {
165 assert(me);
166
167 return fstab_test_option(me->mnt_opts, "_netdev\0") ||
168 fstype_is_network(me->mnt_type);
169 }
170
171 static bool mount_in_initrd(struct mntent *me) {
172 assert(me);
173
174 return fstab_test_option(me->mnt_opts, "x-initrd.mount\0") ||
175 streq(me->mnt_dir, "/usr");
176 }
177
178 static int write_timeout(FILE *f, const char *where, const char *opts,
179 const char *filter, const char *variable) {
180 _cleanup_free_ char *timeout = NULL;
181 char timespan[FORMAT_TIMESPAN_MAX];
182 usec_t u;
183 int r;
184
185 r = fstab_filter_options(opts, filter, NULL, &timeout, NULL);
186 if (r < 0)
187 return log_warning_errno(r, "Failed to parse options: %m");
188 if (r == 0)
189 return 0;
190
191 r = parse_sec(timeout, &u);
192 if (r < 0) {
193 log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
194 return 0;
195 }
196
197 fprintf(f, "%s=%s\n", variable, format_timespan(timespan, sizeof(timespan), u, 0));
198
199 return 0;
200 }
201
202 static int write_idle_timeout(FILE *f, const char *where, const char *opts) {
203 return write_timeout(f, where, opts,
204 "x-systemd.idle-timeout\0", "TimeoutIdleSec");
205 }
206
207 static int write_mount_timeout(FILE *f, const char *where, const char *opts) {
208 return write_timeout(f, where, opts,
209 "x-systemd.mount-timeout\0", "TimeoutSec");
210 }
211
212 static int write_dependency(FILE *f, const char *opts,
213 const char *filter, const char *format) {
214 _cleanup_strv_free_ char **names = NULL, **units = NULL;
215 _cleanup_free_ char *res = NULL;
216 char **s;
217 int r;
218
219 assert(f);
220 assert(opts);
221
222 r = fstab_extract_values(opts, filter, &names);
223 if (r < 0)
224 return log_warning_errno(r, "Failed to parse options: %m");
225 if (r == 0)
226 return 0;
227
228 STRV_FOREACH(s, names) {
229 char *x;
230
231 r = unit_name_mangle_with_suffix(*s, UNIT_NAME_NOGLOB, ".mount", &x);
232 if (r < 0)
233 return log_error_errno(r, "Failed to generate unit name: %m");
234 r = strv_consume(&units, x);
235 if (r < 0)
236 return log_oom();
237 }
238
239 if (units) {
240 res = strv_join(units, " ");
241 if (!res)
242 return log_oom();
243 #pragma GCC diagnostic push
244 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
245 fprintf(f, format, res);
246 #pragma GCC diagnostic pop
247 }
248
249 return 0;
250 }
251
252 static int write_after(FILE *f, const char *opts) {
253 return write_dependency(f, opts, "x-systemd.after", "After=%1$s\n");
254 }
255
256 static int write_requires_after(FILE *f, const char *opts) {
257 return write_dependency(f, opts,
258 "x-systemd.requires", "After=%1$s\nRequires=%1$s\n");
259 }
260
261 static int write_before(FILE *f, const char *opts) {
262 return write_dependency(f, opts,
263 "x-systemd.before", "Before=%1$s\n");
264 }
265
266 static int write_requires_mounts_for(FILE *f, const char *opts) {
267 _cleanup_strv_free_ char **paths = NULL;
268 _cleanup_free_ char *res = NULL;
269 int r;
270
271 assert(f);
272 assert(opts);
273
274 r = fstab_extract_values(opts, "x-systemd.requires-mounts-for", &paths);
275 if (r < 0)
276 return log_warning_errno(r, "Failed to parse options: %m");
277 if (r == 0)
278 return 0;
279
280 res = strv_join(paths, " ");
281 if (!res)
282 return log_oom();
283
284 fprintf(f, "RequiresMountsFor=%s\n", res);
285
286 return 0;
287 }
288
289 static int add_mount(
290 const char *dest,
291 const char *what,
292 const char *where,
293 const char *fstype,
294 const char *opts,
295 int passno,
296 bool noauto,
297 bool nofail,
298 bool automount,
299 const char *post,
300 const char *source) {
301
302 _cleanup_free_ char
303 *name = NULL, *unit = NULL, *lnk = NULL,
304 *automount_name = NULL, *automount_unit = NULL,
305 *filtered = NULL;
306 _cleanup_fclose_ FILE *f = NULL;
307 int r;
308
309 assert(what);
310 assert(where);
311 assert(opts);
312 assert(post);
313 assert(source);
314
315 if (streq_ptr(fstype, "autofs"))
316 return 0;
317
318 if (!is_path(where)) {
319 log_warning("Mount point %s is not a valid path, ignoring.", where);
320 return 0;
321 }
322
323 if (mount_point_is_api(where) ||
324 mount_point_ignore(where))
325 return 0;
326
327 if (path_equal(where, "/")) {
328 if (noauto)
329 log_warning("Ignoring \"noauto\" for root device");
330 if (nofail)
331 log_warning("Ignoring \"nofail\" for root device");
332 if (automount)
333 log_warning("Ignoring automount option for root device");
334
335 noauto = nofail = automount = false;
336 }
337
338 r = unit_name_from_path(where, ".mount", &name);
339 if (r < 0)
340 return log_error_errno(r, "Failed to generate unit name: %m");
341
342 unit = strjoin(dest, "/", name);
343 if (!unit)
344 return log_oom();
345
346 f = fopen(unit, "wxe");
347 if (!f)
348 return log_error_errno(errno,
349 errno == EEXIST ?
350 "Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?" :
351 "Failed to create unit file %s: %m",
352 unit);
353
354 fprintf(f,
355 "# Automatically generated by systemd-fstab-generator\n\n"
356 "[Unit]\n"
357 "SourcePath=%s\n"
358 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
359 source);
360
361 if (!noauto && !nofail && !automount)
362 fprintf(f, "Before=%s\n", post);
363
364 if (!automount && opts) {
365 r = write_after(f, opts);
366 if (r < 0)
367 return r;
368 r = write_requires_after(f, opts);
369 if (r < 0)
370 return r;
371 r = write_before(f, opts);
372 if (r < 0)
373 return r;
374 r = write_requires_mounts_for(f, opts);
375 if (r < 0)
376 return r;
377 }
378
379 if (passno != 0) {
380 r = generator_write_fsck_deps(f, dest, what, where, fstype);
381 if (r < 0)
382 return r;
383 }
384
385 fprintf(f,
386 "\n"
387 "[Mount]\n"
388 "Where=%s\n",
389 where);
390
391 r = write_what(f, what);
392 if (r < 0)
393 return r;
394
395 if (!isempty(fstype) && !streq(fstype, "auto"))
396 fprintf(f, "Type=%s\n", fstype);
397
398 r = generator_write_timeouts(dest, what, where, opts, &filtered);
399 if (r < 0)
400 return r;
401
402 r = write_mount_timeout(f, where, opts);
403 if (r < 0)
404 return r;
405
406 r = write_options(f, filtered);
407 if (r < 0)
408 return r;
409
410 r = fflush_and_check(f);
411 if (r < 0)
412 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
413
414 if (!noauto && !automount) {
415 lnk = strjoin(dest, "/", post, nofail ? ".wants/" : ".requires/", name);
416 if (!lnk)
417 return log_oom();
418
419 mkdir_parents_label(lnk, 0755);
420 if (symlink(unit, lnk) < 0)
421 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
422 }
423
424 if (automount) {
425 r = unit_name_from_path(where, ".automount", &automount_name);
426 if (r < 0)
427 return log_error_errno(r, "Failed to generate unit name: %m");
428
429 automount_unit = strjoin(dest, "/", automount_name);
430 if (!automount_unit)
431 return log_oom();
432
433 fclose(f);
434 f = fopen(automount_unit, "wxe");
435 if (!f)
436 return log_error_errno(errno, "Failed to create unit file %s: %m", automount_unit);
437
438 fprintf(f,
439 "# Automatically generated by systemd-fstab-generator\n\n"
440 "[Unit]\n"
441 "SourcePath=%s\n"
442 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
443 source);
444
445 fprintf(f, "Before=%s\n", post);
446
447 if (opts) {
448 r = write_after(f, opts);
449 if (r < 0)
450 return r;
451 r = write_requires_after(f, opts);
452 if (r < 0)
453 return r;
454 r = write_before(f, opts);
455 if (r < 0)
456 return r;
457 r = write_requires_mounts_for(f, opts);
458 if (r < 0)
459 return r;
460 }
461
462 fprintf(f,
463 "\n"
464 "[Automount]\n"
465 "Where=%s\n",
466 where);
467
468 r = write_idle_timeout(f, where, opts);
469 if (r < 0)
470 return r;
471
472 r = fflush_and_check(f);
473 if (r < 0)
474 return log_error_errno(r, "Failed to write unit file %s: %m", automount_unit);
475
476 free(lnk);
477 lnk = strjoin(dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name);
478 if (!lnk)
479 return log_oom();
480
481 mkdir_parents_label(lnk, 0755);
482 if (symlink(automount_unit, lnk) < 0)
483 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
484 }
485
486 return 0;
487 }
488
489 static int parse_fstab(bool initrd) {
490 _cleanup_endmntent_ FILE *f = NULL;
491 const char *fstab_path;
492 struct mntent *me;
493 int r = 0;
494
495 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
496 f = setmntent(fstab_path, "re");
497 if (!f) {
498 if (errno == ENOENT)
499 return 0;
500
501 return log_error_errno(errno, "Failed to open %s: %m", fstab_path);
502 }
503
504 while ((me = getmntent(f))) {
505 _cleanup_free_ char *where = NULL, *what = NULL;
506 bool noauto, nofail;
507 int k;
508
509 if (initrd && !mount_in_initrd(me))
510 continue;
511
512 what = fstab_node_to_udev_node(me->mnt_fsname);
513 if (!what)
514 return log_oom();
515
516 if (is_device_path(what) && path_is_read_only_fs("sys") > 0) {
517 log_info("Running in a container, ignoring fstab device entry for %s.", what);
518 continue;
519 }
520
521 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
522 if (!where)
523 return log_oom();
524
525 if (is_path(where))
526 path_kill_slashes(where);
527
528 noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
529 nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
530 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
531 what, where, me->mnt_type,
532 yes_no(noauto), yes_no(nofail));
533
534 if (streq(me->mnt_type, "swap"))
535 k = add_swap(what, me, noauto, nofail);
536 else {
537 bool automount;
538 const char *post;
539
540 automount = fstab_test_option(me->mnt_opts,
541 "comment=systemd.automount\0"
542 "x-systemd.automount\0");
543 if (initrd)
544 post = SPECIAL_INITRD_FS_TARGET;
545 else if (mount_is_network(me))
546 post = SPECIAL_REMOTE_FS_TARGET;
547 else
548 post = SPECIAL_LOCAL_FS_TARGET;
549
550 k = add_mount(arg_dest,
551 what,
552 where,
553 me->mnt_type,
554 me->mnt_opts,
555 me->mnt_passno,
556 noauto,
557 nofail,
558 automount,
559 post,
560 fstab_path);
561 }
562
563 if (k < 0)
564 r = k;
565 }
566
567 return r;
568 }
569
570 static int add_sysroot_mount(void) {
571 _cleanup_free_ char *what = NULL;
572 const char *opts;
573 int r;
574
575 if (isempty(arg_root_what)) {
576 log_debug("Could not find a root= entry on the kernel command line.");
577 return 0;
578 }
579
580 if (streq(arg_root_what, "gpt-auto")) {
581 /* This is handled by the gpt-auto generator */
582 log_debug("Skipping root directory handling, as gpt-auto was requested.");
583 return 0;
584 }
585
586 if (path_equal(arg_root_what, "/dev/nfs")) {
587 /* This is handled by the kernel or the initrd */
588 log_debug("Skipping root directory handling, as /dev/nfs was requested.");
589 return 0;
590 }
591
592 what = fstab_node_to_udev_node(arg_root_what);
593 if (!what)
594 return log_oom();
595
596 if (!arg_root_options)
597 opts = arg_root_rw > 0 ? "rw" : "ro";
598 else if (arg_root_rw >= 0 ||
599 !fstab_test_option(arg_root_options, "ro\0" "rw\0"))
600 opts = strjoina(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
601 else
602 opts = arg_root_options;
603
604 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
605
606 if (is_device_path(what)) {
607 r = generator_write_initrd_root_device_deps(arg_dest, what);
608 if (r < 0)
609 return r;
610 }
611
612 return add_mount(arg_dest,
613 what,
614 "/sysroot",
615 arg_root_fstype,
616 opts,
617 is_device_path(what) ? 1 : 0, /* passno */
618 false, /* noauto off */
619 false, /* nofail off */
620 false, /* automount off */
621 SPECIAL_INITRD_ROOT_FS_TARGET,
622 "/proc/cmdline");
623 }
624
625 static int add_sysroot_usr_mount(void) {
626 _cleanup_free_ char *what = NULL;
627 const char *opts;
628
629 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
630 return 0;
631
632 if (arg_root_what && !arg_usr_what) {
633 /* Copy over the root device, in case the /usr mount just differs in a mount option (consider btrfs subvolumes) */
634 arg_usr_what = strdup(arg_root_what);
635 if (!arg_usr_what)
636 return log_oom();
637 }
638
639 if (arg_root_fstype && !arg_usr_fstype) {
640 arg_usr_fstype = strdup(arg_root_fstype);
641 if (!arg_usr_fstype)
642 return log_oom();
643 }
644
645 if (arg_root_options && !arg_usr_options) {
646 arg_usr_options = strdup(arg_root_options);
647 if (!arg_usr_options)
648 return log_oom();
649 }
650
651 if (!arg_usr_what)
652 return 0;
653
654 what = fstab_node_to_udev_node(arg_usr_what);
655 if (!what)
656 return log_oom();
657
658 if (!arg_usr_options)
659 opts = arg_root_rw > 0 ? "rw" : "ro";
660 else if (!fstab_test_option(arg_usr_options, "ro\0" "rw\0"))
661 opts = strjoina(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro");
662 else
663 opts = arg_usr_options;
664
665 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
666 return add_mount(arg_dest,
667 what,
668 "/sysroot/usr",
669 arg_usr_fstype,
670 opts,
671 is_device_path(what) ? 1 : 0, /* passno */
672 false, /* noauto off */
673 false, /* nofail off */
674 false, /* automount off */
675 SPECIAL_INITRD_FS_TARGET,
676 "/proc/cmdline");
677 }
678
679 static int add_volatile_root(void) {
680 const char *from, *to;
681
682 if (arg_volatile_mode != VOLATILE_YES)
683 return 0;
684
685 /* Let's add in systemd-remount-volatile.service which will remount the root device to tmpfs if this is
686 * requested, leaving only /usr from the root mount inside. */
687
688 from = strjoina(SYSTEM_DATA_UNIT_PATH "/systemd-volatile-root.service");
689 to = strjoina(arg_dest, "/" SPECIAL_INITRD_ROOT_FS_TARGET, ".requires/systemd-volatile-root.service");
690
691 (void) mkdir_parents(to, 0755);
692
693 if (symlink(from, to) < 0)
694 return log_error_errno(errno, "Failed to hook in volatile remount service: %m");
695
696 return 0;
697 }
698
699 static int add_volatile_var(void) {
700
701 if (arg_volatile_mode != VOLATILE_STATE)
702 return 0;
703
704 /* If requested, mount /var as tmpfs, but do so only if there's nothing else defined for this. */
705
706 return add_mount(arg_dest_late,
707 "tmpfs",
708 "/var",
709 "tmpfs",
710 "mode=0755",
711 0,
712 false,
713 false,
714 false,
715 SPECIAL_LOCAL_FS_TARGET,
716 "/proc/cmdline");
717 }
718
719 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
720 int r;
721
722 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
723 * instance should take precedence. In the case of multiple rootflags=
724 * or usrflags= the arguments should be concatenated */
725
726 if (STR_IN_SET(key, "fstab", "rd.fstab")) {
727
728 r = value ? parse_boolean(value) : 1;
729 if (r < 0)
730 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
731 else
732 arg_fstab_enabled = r;
733
734 } else if (streq(key, "root")) {
735
736 if (proc_cmdline_value_missing(key, value))
737 return 0;
738
739 if (free_and_strdup(&arg_root_what, value) < 0)
740 return log_oom();
741
742 } else if (streq(key, "rootfstype")) {
743
744 if (proc_cmdline_value_missing(key, value))
745 return 0;
746
747 if (free_and_strdup(&arg_root_fstype, value) < 0)
748 return log_oom();
749
750 } else if (streq(key, "rootflags")) {
751 char *o;
752
753 if (proc_cmdline_value_missing(key, value))
754 return 0;
755
756 o = arg_root_options ?
757 strjoin(arg_root_options, ",", value) :
758 strdup(value);
759 if (!o)
760 return log_oom();
761
762 free(arg_root_options);
763 arg_root_options = o;
764 } else if (streq(key, "roothash")) {
765
766 if (proc_cmdline_value_missing(key, value))
767 return 0;
768
769 if (free_and_strdup(&arg_root_hash, value) < 0)
770 return log_oom();
771
772 } else if (streq(key, "mount.usr")) {
773
774 if (proc_cmdline_value_missing(key, value))
775 return 0;
776
777 if (free_and_strdup(&arg_usr_what, value) < 0)
778 return log_oom();
779
780 } else if (streq(key, "mount.usrfstype")) {
781
782 if (proc_cmdline_value_missing(key, value))
783 return 0;
784
785 if (free_and_strdup(&arg_usr_fstype, value) < 0)
786 return log_oom();
787
788 } else if (streq(key, "mount.usrflags")) {
789 char *o;
790
791 if (proc_cmdline_value_missing(key, value))
792 return 0;
793
794 o = arg_usr_options ?
795 strjoin(arg_usr_options, ",", value) :
796 strdup(value);
797 if (!o)
798 return log_oom();
799
800 free(arg_usr_options);
801 arg_usr_options = o;
802
803 } else if (streq(key, "rw") && !value)
804 arg_root_rw = true;
805 else if (streq(key, "ro") && !value)
806 arg_root_rw = false;
807 else if (streq(key, "systemd.volatile")) {
808 VolatileMode m;
809
810 if (value) {
811 m = volatile_mode_from_string(value);
812 if (m < 0)
813 log_warning("Failed to parse systemd.volatile= argument: %s", value);
814 else
815 arg_volatile_mode = m;
816 } else
817 arg_volatile_mode = VOLATILE_YES;
818 }
819
820 return 0;
821 }
822
823 static int determine_root(void) {
824 /* If we have a root hash but no root device then Verity is used, and we use the "root" DM device as root. */
825
826 if (arg_root_what)
827 return 0;
828
829 if (!arg_root_hash)
830 return 0;
831
832 arg_root_what = strdup("/dev/mapper/root");
833 if (!arg_root_what)
834 return log_oom();
835
836 log_info("Using verity root device %s.", arg_root_what);
837
838 return 1;
839 }
840
841 int main(int argc, char *argv[]) {
842 int r = 0;
843
844 if (argc > 1 && argc != 4) {
845 log_error("This program takes three or no arguments.");
846 return EXIT_FAILURE;
847 }
848
849 if (argc > 1)
850 arg_dest = argv[1];
851 if (argc > 3)
852 arg_dest_late = argv[3];
853
854 log_set_target(LOG_TARGET_SAFE);
855 log_parse_environment();
856 log_open();
857
858 umask(0022);
859
860 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
861 if (r < 0)
862 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
863
864 (void) determine_root();
865
866 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
867 if (in_initrd()) {
868 int k;
869
870 r = add_sysroot_mount();
871
872 k = add_sysroot_usr_mount();
873 if (k < 0)
874 r = k;
875
876 k = add_volatile_root();
877 if (k < 0)
878 r = k;
879 } else
880 r = add_volatile_var();
881
882 /* Honour /etc/fstab only when that's enabled */
883 if (arg_fstab_enabled) {
884 int k;
885
886 log_debug("Parsing /etc/fstab");
887
888 /* Parse the local /etc/fstab, possibly from the initrd */
889 k = parse_fstab(false);
890 if (k < 0)
891 r = k;
892
893 /* If running in the initrd also parse the /etc/fstab from the host */
894 if (in_initrd()) {
895 log_debug("Parsing /sysroot/etc/fstab");
896
897 k = parse_fstab(true);
898 if (k < 0)
899 r = k;
900 }
901 }
902
903 free(arg_root_what);
904 free(arg_root_fstype);
905 free(arg_root_options);
906 free(arg_root_hash);
907
908 free(arg_usr_what);
909 free(arg_usr_fstype);
910 free(arg_usr_options);
911
912 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
913 }