]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/fstab-generator/fstab-generator.c
fstab-generator: don't process root= if it happens to be "gpt-auto" (#3452)
[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
46 static const char *arg_dest = "/tmp";
47 static bool arg_fstab_enabled = true;
48 static char *arg_root_what = NULL;
49 static char *arg_root_fstype = NULL;
50 static char *arg_root_options = NULL;
51 static int arg_root_rw = -1;
52 static char *arg_usr_what = NULL;
53 static char *arg_usr_fstype = NULL;
54 static char *arg_usr_options = NULL;
55
56 static int add_swap(
57 const char *what,
58 struct mntent *me,
59 bool noauto,
60 bool nofail) {
61
62 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
63 _cleanup_fclose_ FILE *f = NULL;
64 int r;
65
66 assert(what);
67 assert(me);
68
69 if (access("/proc/swaps", F_OK) < 0) {
70 log_info("Swap not supported, ignoring fstab swap entry for %s.", what);
71 return 0;
72 }
73
74 if (detect_container() > 0) {
75 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
76 return 0;
77 }
78
79 r = unit_name_from_path(what, ".swap", &name);
80 if (r < 0)
81 return log_error_errno(r, "Failed to generate unit name: %m");
82
83 unit = strjoin(arg_dest, "/", name, NULL);
84 if (!unit)
85 return log_oom();
86
87 f = fopen(unit, "wxe");
88 if (!f) {
89 if (errno == EEXIST)
90 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
91 else
92 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
93 return -errno;
94 }
95
96 fprintf(f,
97 "# Automatically generated by systemd-fstab-generator\n\n"
98 "[Unit]\n"
99 "SourcePath=/etc/fstab\n"
100 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
101 "[Swap]\n"
102 "What=%s\n",
103 what);
104
105 if (!isempty(me->mnt_opts) && !streq(me->mnt_opts, "defaults"))
106 fprintf(f, "Options=%s\n", me->mnt_opts);
107
108 r = fflush_and_check(f);
109 if (r < 0)
110 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
111
112 /* use what as where, to have a nicer error message */
113 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
114 if (r < 0)
115 return r;
116
117 if (!noauto) {
118 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET,
119 nofail ? ".wants/" : ".requires/", name, NULL);
120 if (!lnk)
121 return log_oom();
122
123 mkdir_parents_label(lnk, 0755);
124 if (symlink(unit, lnk) < 0)
125 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
126 }
127
128 return 0;
129 }
130
131 static bool mount_is_network(struct mntent *me) {
132 assert(me);
133
134 return fstab_test_option(me->mnt_opts, "_netdev\0") ||
135 fstype_is_network(me->mnt_type);
136 }
137
138 static bool mount_in_initrd(struct mntent *me) {
139 assert(me);
140
141 return fstab_test_option(me->mnt_opts, "x-initrd.mount\0") ||
142 streq(me->mnt_dir, "/usr");
143 }
144
145 static int write_idle_timeout(FILE *f, const char *where, const char *opts) {
146 _cleanup_free_ char *timeout = NULL;
147 char timespan[FORMAT_TIMESPAN_MAX];
148 usec_t u;
149 int r;
150
151 r = fstab_filter_options(opts, "x-systemd.idle-timeout\0", NULL, &timeout, NULL);
152 if (r < 0)
153 return log_warning_errno(r, "Failed to parse options: %m");
154 if (r == 0)
155 return 0;
156
157 r = parse_sec(timeout, &u);
158 if (r < 0) {
159 log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
160 return 0;
161 }
162
163 fprintf(f, "TimeoutIdleSec=%s\n", format_timespan(timespan, sizeof(timespan), u, 0));
164
165 return 0;
166 }
167
168 static int write_requires_after(FILE *f, const char *opts) {
169 _cleanup_strv_free_ char **names = NULL, **units = NULL;
170 _cleanup_free_ char *res = NULL;
171 char **s;
172 int r;
173
174 assert(f);
175 assert(opts);
176
177 r = fstab_extract_values(opts, "x-systemd.requires", &names);
178 if (r < 0)
179 return log_warning_errno(r, "Failed to parse options: %m");
180 if (r == 0)
181 return 0;
182
183 STRV_FOREACH(s, names) {
184 char *x;
185
186 r = unit_name_mangle_with_suffix(*s, UNIT_NAME_NOGLOB, ".mount", &x);
187 if (r < 0)
188 return log_error_errno(r, "Failed to generate unit name: %m");
189 r = strv_consume(&units, x);
190 if (r < 0)
191 return log_oom();
192 }
193
194 if (units) {
195 res = strv_join(units, " ");
196 if (!res)
197 return log_oom();
198 fprintf(f, "After=%1$s\nRequires=%1$s\n", res);
199 }
200
201 return 0;
202 }
203
204 static int write_requires_mounts_for(FILE *f, const char *opts) {
205 _cleanup_strv_free_ char **paths = NULL;
206 _cleanup_free_ char *res = NULL;
207 int r;
208
209 assert(f);
210 assert(opts);
211
212 r = fstab_extract_values(opts, "x-systemd.requires-mounts-for", &paths);
213 if (r < 0)
214 return log_warning_errno(r, "Failed to parse options: %m");
215 if (r == 0)
216 return 0;
217
218 res = strv_join(paths, " ");
219 if (!res)
220 return log_oom();
221
222 fprintf(f, "RequiresMountsFor=%s\n", res);
223
224 return 0;
225 }
226
227 static int add_mount(
228 const char *what,
229 const char *where,
230 const char *fstype,
231 const char *opts,
232 int passno,
233 bool noauto,
234 bool nofail,
235 bool automount,
236 const char *post,
237 const char *source) {
238
239 _cleanup_free_ char
240 *name = NULL, *unit = NULL, *lnk = NULL,
241 *automount_name = NULL, *automount_unit = NULL,
242 *filtered = NULL;
243 _cleanup_fclose_ FILE *f = NULL;
244 int r;
245
246 assert(what);
247 assert(where);
248 assert(opts);
249 assert(post);
250 assert(source);
251
252 if (streq_ptr(fstype, "autofs"))
253 return 0;
254
255 if (!is_path(where)) {
256 log_warning("Mount point %s is not a valid path, ignoring.", where);
257 return 0;
258 }
259
260 if (mount_point_is_api(where) ||
261 mount_point_ignore(where))
262 return 0;
263
264 if (path_equal(where, "/")) {
265 if (noauto)
266 log_warning("Ignoring \"noauto\" for root device");
267 if (nofail)
268 log_warning("Ignoring \"nofail\" for root device");
269 if (automount)
270 log_warning("Ignoring automount option for root device");
271
272 noauto = nofail = automount = false;
273 }
274
275 r = unit_name_from_path(where, ".mount", &name);
276 if (r < 0)
277 return log_error_errno(r, "Failed to generate unit name: %m");
278
279 unit = strjoin(arg_dest, "/", name, NULL);
280 if (!unit)
281 return log_oom();
282
283 f = fopen(unit, "wxe");
284 if (!f) {
285 if (errno == EEXIST)
286 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
287 else
288 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
289 return -errno;
290 }
291
292 fprintf(f,
293 "# Automatically generated by systemd-fstab-generator\n\n"
294 "[Unit]\n"
295 "SourcePath=%s\n"
296 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
297 source);
298
299 if (!noauto && !nofail && !automount)
300 fprintf(f, "Before=%s\n", post);
301
302 if (!automount && opts) {
303 r = write_requires_after(f, opts);
304 if (r < 0)
305 return r;
306 r = write_requires_mounts_for(f, opts);
307 if (r < 0)
308 return r;
309 }
310
311 if (passno != 0) {
312 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
313 if (r < 0)
314 return r;
315 }
316
317 fprintf(f,
318 "\n"
319 "[Mount]\n"
320 "What=%s\n"
321 "Where=%s\n",
322 what,
323 where);
324
325 if (!isempty(fstype) && !streq(fstype, "auto"))
326 fprintf(f, "Type=%s\n", fstype);
327
328 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
329 if (r < 0)
330 return r;
331
332 if (!isempty(filtered) && !streq(filtered, "defaults"))
333 fprintf(f, "Options=%s\n", filtered);
334
335 r = fflush_and_check(f);
336 if (r < 0)
337 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
338
339 if (!noauto && !automount) {
340 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", name, NULL);
341 if (!lnk)
342 return log_oom();
343
344 mkdir_parents_label(lnk, 0755);
345 if (symlink(unit, lnk) < 0)
346 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
347 }
348
349 if (automount) {
350 r = unit_name_from_path(where, ".automount", &automount_name);
351 if (r < 0)
352 return log_error_errno(r, "Failed to generate unit name: %m");
353
354 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
355 if (!automount_unit)
356 return log_oom();
357
358 fclose(f);
359 f = fopen(automount_unit, "wxe");
360 if (!f)
361 return log_error_errno(errno, "Failed to create unit file %s: %m", automount_unit);
362
363 fprintf(f,
364 "# Automatically generated by systemd-fstab-generator\n\n"
365 "[Unit]\n"
366 "SourcePath=%s\n"
367 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
368 source);
369
370 fprintf(f, "Before=%s\n", post);
371
372 if (opts) {
373 r = write_requires_after(f, opts);
374 if (r < 0)
375 return r;
376 r = write_requires_mounts_for(f, opts);
377 if (r < 0)
378 return r;
379 }
380
381 fprintf(f,
382 "\n"
383 "[Automount]\n"
384 "Where=%s\n",
385 where);
386
387 r = write_idle_timeout(f, where, opts);
388 if (r < 0)
389 return r;
390
391 r = fflush_and_check(f);
392 if (r < 0)
393 return log_error_errno(r, "Failed to write unit file %s: %m", automount_unit);
394
395 free(lnk);
396 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
397 if (!lnk)
398 return log_oom();
399
400 mkdir_parents_label(lnk, 0755);
401 if (symlink(automount_unit, lnk) < 0)
402 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
403 }
404
405 return 0;
406 }
407
408 static int parse_fstab(bool initrd) {
409 _cleanup_endmntent_ FILE *f = NULL;
410 const char *fstab_path;
411 struct mntent *me;
412 int r = 0;
413
414 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
415 f = setmntent(fstab_path, "re");
416 if (!f) {
417 if (errno == ENOENT)
418 return 0;
419
420 log_error_errno(errno, "Failed to open %s: %m", fstab_path);
421 return -errno;
422 }
423
424 while ((me = getmntent(f))) {
425 _cleanup_free_ char *where = NULL, *what = NULL;
426 bool noauto, nofail;
427 int k;
428
429 if (initrd && !mount_in_initrd(me))
430 continue;
431
432 what = fstab_node_to_udev_node(me->mnt_fsname);
433 if (!what)
434 return log_oom();
435
436 if (is_device_path(what) && path_is_read_only_fs("sys") > 0) {
437 log_info("Running in a container, ignoring fstab device entry for %s.", what);
438 continue;
439 }
440
441 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
442 if (!where)
443 return log_oom();
444
445 if (is_path(where))
446 path_kill_slashes(where);
447
448 noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
449 nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
450 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
451 what, where, me->mnt_type,
452 yes_no(noauto), yes_no(nofail));
453
454 if (streq(me->mnt_type, "swap"))
455 k = add_swap(what, me, noauto, nofail);
456 else {
457 bool automount;
458 const char *post;
459
460 automount = fstab_test_option(me->mnt_opts,
461 "comment=systemd.automount\0"
462 "x-systemd.automount\0");
463 if (initrd)
464 post = SPECIAL_INITRD_FS_TARGET;
465 else if (mount_is_network(me))
466 post = SPECIAL_REMOTE_FS_TARGET;
467 else
468 post = SPECIAL_LOCAL_FS_TARGET;
469
470 k = add_mount(what,
471 where,
472 me->mnt_type,
473 me->mnt_opts,
474 me->mnt_passno,
475 noauto,
476 nofail,
477 automount,
478 post,
479 fstab_path);
480 }
481
482 if (k < 0)
483 r = k;
484 }
485
486 return r;
487 }
488
489 static int add_sysroot_mount(void) {
490 _cleanup_free_ char *what = NULL;
491 const char *opts;
492 int r;
493
494 if (isempty(arg_root_what)) {
495 log_debug("Could not find a root= entry on the kernel command line.");
496 return 0;
497 }
498
499 if (streq(arg_root_what, "gpt-auto")) {
500 /* This is handled by the gpt-auto generator */
501 log_debug("Skipping root directory handling, as gpt-auto was requested.");
502 return 0;
503 }
504
505 what = fstab_node_to_udev_node(arg_root_what);
506 if (!what)
507 return log_oom();
508
509 if (!arg_root_options)
510 opts = arg_root_rw > 0 ? "rw" : "ro";
511 else if (arg_root_rw >= 0 ||
512 !fstab_test_option(arg_root_options, "ro\0" "rw\0"))
513 opts = strjoina(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
514 else
515 opts = arg_root_options;
516
517 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
518
519 if (is_device_path(what)) {
520 r = generator_write_initrd_root_device_deps(arg_dest, what);
521 if (r < 0)
522 return r;
523 }
524
525 return add_mount(what,
526 "/sysroot",
527 arg_root_fstype,
528 opts,
529 is_device_path(what) ? 1 : 0,
530 false,
531 false,
532 false,
533 SPECIAL_INITRD_ROOT_FS_TARGET,
534 "/proc/cmdline");
535 }
536
537 static int add_sysroot_usr_mount(void) {
538 _cleanup_free_ char *what = NULL;
539 const char *opts;
540
541 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
542 return 0;
543
544 if (arg_root_what && !arg_usr_what) {
545 arg_usr_what = strdup(arg_root_what);
546
547 if (!arg_usr_what)
548 return log_oom();
549 }
550
551 if (arg_root_fstype && !arg_usr_fstype) {
552 arg_usr_fstype = strdup(arg_root_fstype);
553
554 if (!arg_usr_fstype)
555 return log_oom();
556 }
557
558 if (arg_root_options && !arg_usr_options) {
559 arg_usr_options = strdup(arg_root_options);
560
561 if (!arg_usr_options)
562 return log_oom();
563 }
564
565 if (!arg_usr_what)
566 return 0;
567
568 what = fstab_node_to_udev_node(arg_usr_what);
569 if (!path_is_absolute(what)) {
570 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
571 return -1;
572 }
573
574 if (!arg_usr_options)
575 opts = arg_root_rw > 0 ? "rw" : "ro";
576 else if (!fstab_test_option(arg_usr_options, "ro\0" "rw\0"))
577 opts = strjoina(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro");
578 else
579 opts = arg_usr_options;
580
581 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
582 return add_mount(what,
583 "/sysroot/usr",
584 arg_usr_fstype,
585 opts,
586 1,
587 false,
588 false,
589 false,
590 SPECIAL_INITRD_FS_TARGET,
591 "/proc/cmdline");
592 }
593
594 static int parse_proc_cmdline_item(const char *key, const char *value) {
595 int r;
596
597 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
598 * instance should take precedence. In the case of multiple rootflags=
599 * or usrflags= the arguments should be concatenated */
600
601 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
602
603 r = parse_boolean(value);
604 if (r < 0)
605 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
606 else
607 arg_fstab_enabled = r;
608
609 } else if (streq(key, "root") && value) {
610
611 if (free_and_strdup(&arg_root_what, value) < 0)
612 return log_oom();
613
614 } else if (streq(key, "rootfstype") && value) {
615
616 if (free_and_strdup(&arg_root_fstype, value) < 0)
617 return log_oom();
618
619 } else if (streq(key, "rootflags") && value) {
620 char *o;
621
622 o = arg_root_options ?
623 strjoin(arg_root_options, ",", value, NULL) :
624 strdup(value);
625 if (!o)
626 return log_oom();
627
628 free(arg_root_options);
629 arg_root_options = o;
630
631 } else if (streq(key, "mount.usr") && value) {
632
633 if (free_and_strdup(&arg_usr_what, value) < 0)
634 return log_oom();
635
636 } else if (streq(key, "mount.usrfstype") && value) {
637
638 if (free_and_strdup(&arg_usr_fstype, value) < 0)
639 return log_oom();
640
641 } else if (streq(key, "mount.usrflags") && value) {
642 char *o;
643
644 o = arg_usr_options ?
645 strjoin(arg_usr_options, ",", value, NULL) :
646 strdup(value);
647 if (!o)
648 return log_oom();
649
650 free(arg_usr_options);
651 arg_usr_options = o;
652
653 } else if (streq(key, "rw") && !value)
654 arg_root_rw = true;
655 else if (streq(key, "ro") && !value)
656 arg_root_rw = false;
657
658 return 0;
659 }
660
661 int main(int argc, char *argv[]) {
662 int r = 0;
663
664 if (argc > 1 && argc != 4) {
665 log_error("This program takes three or no arguments.");
666 return EXIT_FAILURE;
667 }
668
669 if (argc > 1)
670 arg_dest = argv[1];
671
672 log_set_target(LOG_TARGET_SAFE);
673 log_parse_environment();
674 log_open();
675
676 umask(0022);
677
678 r = parse_proc_cmdline(parse_proc_cmdline_item);
679 if (r < 0)
680 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
681
682 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
683 if (in_initrd()) {
684 r = add_sysroot_mount();
685 if (r == 0)
686 r = add_sysroot_usr_mount();
687 }
688
689 /* Honour /etc/fstab only when that's enabled */
690 if (arg_fstab_enabled) {
691 int k;
692
693 log_debug("Parsing /etc/fstab");
694
695 /* Parse the local /etc/fstab, possibly from the initrd */
696 k = parse_fstab(false);
697 if (k < 0)
698 r = k;
699
700 /* If running in the initrd also parse the /etc/fstab from the host */
701 if (in_initrd()) {
702 log_debug("Parsing /sysroot/etc/fstab");
703
704 k = parse_fstab(true);
705 if (k < 0)
706 r = k;
707 }
708 }
709
710 free(arg_root_what);
711 free(arg_root_fstype);
712 free(arg_root_options);
713
714 free(arg_usr_what);
715 free(arg_usr_fstype);
716 free(arg_usr_options);
717
718 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
719 }