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