]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/fstab-generator/fstab-generator.c
build-sys: efi - use $EFI_LIB_DIR
[thirdparty/systemd.git] / src / fstab-generator / fstab-generator.c
CommitLineData
6b1dc2bd
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <stdio.h>
23#include <mntent.h>
24#include <errno.h>
25#include <string.h>
26#include <unistd.h>
27
28#include "log.h"
29#include "util.h"
30#include "unit-name.h"
31#include "path-util.h"
d15d0333 32#include "fstab-util.h"
6b1dc2bd
LP
33#include "mount-setup.h"
34#include "special.h"
35#include "mkdir.h"
e48fdd84 36#include "generator.h"
059cb385 37#include "strv.h"
689aede8 38#include "virt.h"
6b1dc2bd
LP
39
40static const char *arg_dest = "/tmp";
e48fdd84 41static bool arg_fstab_enabled = true;
6db615c1
LP
42static char *arg_root_what = NULL;
43static char *arg_root_fstype = NULL;
44static char *arg_root_options = NULL;
45static int arg_root_rw = -1;
9f103625
TH
46static char *arg_usr_what = NULL;
47static char *arg_usr_fstype = NULL;
48static char *arg_usr_options = NULL;
6b1dc2bd 49
5607d856
ZJS
50static int add_swap(
51 const char *what,
52 struct mntent *me,
53 bool noauto,
54 bool nofail) {
55
e0952d9d 56 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL, *filtered = NULL;
7fd1b19b 57 _cleanup_fclose_ FILE *f = NULL;
6b1dc2bd 58 int r, pri = -1;
e0952d9d 59 const char *opts;
6b1dc2bd
LP
60
61 assert(what);
62 assert(me);
63
00b4ffde
LP
64 if (access("/proc/swaps", F_OK) < 0) {
65 log_info("Swap not supported, ignoring fstab swap entry for %s.", what);
66 return 0;
67 }
68
689aede8
LP
69 if (detect_container(NULL) > 0) {
70 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
71 return 0;
72 }
73
e0952d9d
ZJS
74 opts = me->mnt_opts;
75 r = fstab_find_pri(opts, &pri);
76 if (r < 0) {
77 log_error_errno(r, "Failed to parse priority, ignoring: %m");
78
79 /* Remove invalid pri field */
80 r = fstab_filter_options(opts, "pri\0", NULL, NULL, &filtered);
81 if (r < 0)
82 return log_error_errno(r, "Failed to parse options: %m");
83 opts = filtered;
84 }
4f52d3fe 85
6b1dc2bd 86 name = unit_name_from_path(what, ".swap");
d0aa9ce5
ZJS
87 if (!name)
88 return log_oom();
6b1dc2bd 89
b7def684 90 unit = strjoin(arg_dest, "/", name, NULL);
d0aa9ce5
ZJS
91 if (!unit)
92 return log_oom();
6b1dc2bd
LP
93
94 f = fopen(unit, "wxe");
95 if (!f) {
67ab5f76
TG
96 if (errno == EEXIST)
97 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
98 else
56f64d95 99 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
d0aa9ce5 100 return -errno;
6b1dc2bd
LP
101 }
102
6b1dc2bd 103 fprintf(f,
64347fc2
TG
104 "# Automatically generated by systemd-fstab-generator\n\n"
105 "[Unit]\n"
c3834f9b
LP
106 "SourcePath=/etc/fstab\n"
107 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
6b1dc2bd
LP
108 "[Swap]\n"
109 "What=%s\n",
110 what);
111
47cb901e
LP
112 /* Note that we currently pass the priority field twice, once
113 * in Priority=, and once in Options= */
6b1dc2bd 114 if (pri >= 0)
4f52d3fe
ZJS
115 fprintf(f, "Priority=%i\n", pri);
116
e0952d9d
ZJS
117 if (!isempty(opts) && !streq(opts, "defaults"))
118 fprintf(f, "Options=%s\n", opts);
6b1dc2bd 119
47cb901e 120 r = fflush_and_check(f);
23bbb0de
MS
121 if (r < 0)
122 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
6b1dc2bd 123
b3208b66 124 /* use what as where, to have a nicer error message */
e0952d9d 125 r = generator_write_timeouts(arg_dest, what, what, opts, NULL);
b3208b66
ZJS
126 if (r < 0)
127 return r;
128
4e82fe52 129 if (!noauto) {
5607d856
ZJS
130 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET,
131 nofail ? ".wants/" : ".requires/", name, NULL);
4e82fe52
TG
132 if (!lnk)
133 return log_oom();
134
135 mkdir_parents_label(lnk, 0755);
4a62c710
MS
136 if (symlink(unit, lnk) < 0)
137 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
4e82fe52
TG
138 }
139
d0aa9ce5 140 return 0;
6b1dc2bd
LP
141}
142
6b1dc2bd
LP
143static bool mount_is_network(struct mntent *me) {
144 assert(me);
145
b9f111b9
ZJS
146 return fstab_test_option(me->mnt_opts, "_netdev\0") ||
147 fstype_is_network(me->mnt_type);
6b1dc2bd
LP
148}
149
3d22d1ab
TG
150static bool mount_in_initrd(struct mntent *me) {
151 assert(me);
152
b9f111b9
ZJS
153 return fstab_test_option(me->mnt_opts, "x-initrd.mount\0") ||
154 streq(me->mnt_dir, "/usr");
3d22d1ab
TG
155}
156
e8d2f6cd
LP
157static int add_mount(
158 const char *what,
159 const char *where,
6db615c1 160 const char *fstype,
e8d2f6cd
LP
161 const char *opts,
162 int passno,
163 bool noauto,
164 bool nofail,
165 bool automount,
e8d2f6cd 166 const char *post,
e8d2f6cd 167 const char *source) {
e48fdd84 168
7fd1b19b 169 _cleanup_free_ char
1dc2ced4 170 *name = NULL, *unit = NULL, *lnk = NULL,
29686440
ZJS
171 *automount_name = NULL, *automount_unit = NULL,
172 *filtered = NULL;
7fd1b19b 173 _cleanup_fclose_ FILE *f = NULL;
94192cda 174 int r;
6b1dc2bd
LP
175
176 assert(what);
177 assert(where);
5e398e54
TG
178 assert(opts);
179 assert(source);
6b1dc2bd 180
6db615c1 181 if (streq_ptr(fstype, "autofs"))
6b1dc2bd
LP
182 return 0;
183
184 if (!is_path(where)) {
185 log_warning("Mount point %s is not a valid path, ignoring.", where);
186 return 0;
187 }
188
189 if (mount_point_is_api(where) ||
190 mount_point_ignore(where))
191 return 0;
192
e48fdd84 193 if (path_equal(where, "/")) {
5ecdcf41 194 /* The root disk is not an option */
e48fdd84
LP
195 automount = false;
196 noauto = false;
197 nofail = false;
198 }
199
6b1dc2bd 200 name = unit_name_from_path(where, ".mount");
d0aa9ce5
ZJS
201 if (!name)
202 return log_oom();
6b1dc2bd 203
b7def684 204 unit = strjoin(arg_dest, "/", name, NULL);
d0aa9ce5
ZJS
205 if (!unit)
206 return log_oom();
6b1dc2bd
LP
207
208 f = fopen(unit, "wxe");
209 if (!f) {
67ab5f76
TG
210 if (errno == EEXIST)
211 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
212 else
56f64d95 213 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
d0aa9ce5 214 return -errno;
6b1dc2bd
LP
215 }
216
5e398e54 217 fprintf(f,
c3834f9b
LP
218 "# Automatically generated by systemd-fstab-generator\n\n"
219 "[Unit]\n"
220 "SourcePath=%s\n"
221 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
222 source);
6b1dc2bd 223
700e07ff 224 if (post && !noauto && !nofail && !automount)
5ecdcf41 225 fprintf(f, "Before=%s\n", post);
6b1dc2bd 226
e48fdd84 227 if (passno != 0) {
6db615c1 228 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
e48fdd84
LP
229 if (r < 0)
230 return r;
231 }
64e70e4b 232
6b1dc2bd
LP
233 fprintf(f,
234 "\n"
235 "[Mount]\n"
236 "What=%s\n"
6db615c1 237 "Where=%s\n",
6b1dc2bd 238 what,
6db615c1
LP
239 where);
240
241 if (!isempty(fstype) && !streq(fstype, "auto"))
242 fprintf(f, "Type=%s\n", fstype);
6b1dc2bd 243
29686440
ZJS
244 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
245 if (r < 0)
246 return r;
247
248 if (!isempty(filtered) && !streq(filtered, "defaults"))
249 fprintf(f, "Options=%s\n", filtered);
5e398e54 250
6b1dc2bd 251 fflush(f);
4a62c710
MS
252 if (ferror(f))
253 return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
6b1dc2bd 254
5ecdcf41
LP
255 if (!noauto && post) {
256 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
257 if (!lnk)
258 return log_oom();
259
260 mkdir_parents_label(lnk, 0755);
4a62c710
MS
261 if (symlink(unit, lnk) < 0)
262 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
6b1dc2bd
LP
263 }
264
e48fdd84 265 if (automount) {
6b1dc2bd 266 automount_name = unit_name_from_path(where, ".automount");
01264ad1 267 if (!automount_name)
d0aa9ce5 268 return log_oom();
6b1dc2bd 269
b7def684 270 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
d0aa9ce5
ZJS
271 if (!automount_unit)
272 return log_oom();
6b1dc2bd
LP
273
274 fclose(f);
275 f = fopen(automount_unit, "wxe");
4a62c710
MS
276 if (!f)
277 return log_error_errno(errno, "Failed to create unit file %s: %m", automount_unit);
6b1dc2bd
LP
278
279 fprintf(f,
280 "# Automatically generated by systemd-fstab-generator\n\n"
281 "[Unit]\n"
c3834f9b
LP
282 "SourcePath=%s\n"
283 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
700e07ff
HH
284 source);
285
286 if (post)
287 fprintf(f,
e48fdd84 288 "Before=%s\n",
700e07ff
HH
289 post);
290
291 fprintf(f,
6b1dc2bd
LP
292 "[Automount]\n"
293 "Where=%s\n",
6b1dc2bd
LP
294 where);
295
296 fflush(f);
4a62c710
MS
297 if (ferror(f))
298 return log_error_errno(errno, "Failed to write unit file %s: %m", automount_unit);
6b1dc2bd
LP
299
300 free(lnk);
b7def684 301 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
d0aa9ce5
ZJS
302 if (!lnk)
303 return log_oom();
6b1dc2bd 304
d2e54fae 305 mkdir_parents_label(lnk, 0755);
4a62c710
MS
306 if (symlink(automount_unit, lnk) < 0)
307 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
6b1dc2bd
LP
308 }
309
d0aa9ce5 310 return 0;
6b1dc2bd
LP
311}
312
e48fdd84 313static int parse_fstab(bool initrd) {
6db615c1 314 _cleanup_endmntent_ FILE *f = NULL;
e48fdd84 315 const char *fstab_path;
6b1dc2bd 316 struct mntent *me;
e48fdd84 317 int r = 0;
6b1dc2bd 318
e48fdd84
LP
319 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
320 f = setmntent(fstab_path, "re");
6b1dc2bd
LP
321 if (!f) {
322 if (errno == ENOENT)
323 return 0;
324
56f64d95 325 log_error_errno(errno, "Failed to open %s: %m", fstab_path);
6b1dc2bd
LP
326 return -errno;
327 }
328
329 while ((me = getmntent(f))) {
7fd1b19b 330 _cleanup_free_ char *where = NULL, *what = NULL;
5607d856 331 bool noauto, nofail;
6b1dc2bd
LP
332 int k;
333
3d22d1ab
TG
334 if (initrd && !mount_in_initrd(me))
335 continue;
336
6b1dc2bd 337 what = fstab_node_to_udev_node(me->mnt_fsname);
e48fdd84
LP
338 if (!what)
339 return log_oom();
340
00b4ffde 341 if (is_device_path(what) && path_is_read_only_fs("sys") > 0) {
689aede8
LP
342 log_info("Running in a container, ignoring fstab device entry for %s.", what);
343 continue;
344 }
345
e48fdd84
LP
346 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
347 if (!where)
5862d652 348 return log_oom();
6b1dc2bd 349
ec6ceb18 350 if (is_path(where))
6b1dc2bd
LP
351 path_kill_slashes(where);
352
b9f111b9
ZJS
353 noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
354 nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
5607d856
ZJS
355 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
356 what, where, me->mnt_type,
357 yes_no(noauto), yes_no(nofail));
6b1dc2bd
LP
358
359 if (streq(me->mnt_type, "swap"))
5607d856 360 k = add_swap(what, me, noauto, nofail);
5e398e54 361 else {
5607d856 362 bool automount;
80c3b720 363 const char *post;
5e398e54 364
b9f111b9
ZJS
365 automount = fstab_test_option(me->mnt_opts,
366 "comment=systemd.automount\0"
367 "x-systemd.automount\0");
e48fdd84 368 if (initrd)
700e07ff 369 post = SPECIAL_INITRD_FS_TARGET;
e48fdd84 370 else if (mount_in_initrd(me))
9e5f0f92 371 post = SPECIAL_INITRD_ROOT_FS_TARGET;
e48fdd84 372 else if (mount_is_network(me))
0c17fbce 373 post = SPECIAL_REMOTE_FS_TARGET;
e48fdd84 374 else
0c17fbce 375 post = SPECIAL_LOCAL_FS_TARGET;
5e398e54 376
6db615c1
LP
377 k = add_mount(what,
378 where,
379 me->mnt_type,
380 me->mnt_opts,
381 me->mnt_passno,
382 noauto,
383 nofail,
384 automount,
385 post,
386 fstab_path);
5e398e54 387 }
6b1dc2bd 388
6b1dc2bd
LP
389 if (k < 0)
390 r = k;
391 }
392
6b1dc2bd
LP
393 return r;
394}
395
6db615c1 396static int add_root_mount(void) {
75a59316
ZJS
397 _cleanup_free_ char *what = NULL;
398 const char *opts;
5e398e54 399
093c2cfe
TH
400 if (isempty(arg_root_what)) {
401 log_debug("Could not find a root= entry on the kernel command line.");
402 return 0;
135b5212 403 }
5e398e54 404
093c2cfe
TH
405 what = fstab_node_to_udev_node(arg_root_what);
406 if (!what)
171181bc 407 return log_oom();
093c2cfe 408
6db615c1 409 if (!arg_root_options)
75a59316
ZJS
410 opts = arg_root_rw > 0 ? "rw" : "ro";
411 else if (arg_root_rw >= 0 ||
d15d0333 412 !fstab_test_option(arg_root_options, "ro\0" "rw\0"))
63c372cb 413 opts = strjoina(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
75a59316
ZJS
414 else
415 opts = arg_root_options;
5e398e54 416
6db615c1
LP
417 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
418 return add_mount(what,
419 "/sysroot",
420 arg_root_fstype,
75a59316 421 opts,
093c2cfe 422 is_device_path(what) ? 1 : 0,
5ecdcf41
LP
423 false,
424 false,
6db615c1
LP
425 false,
426 SPECIAL_INITRD_ROOT_FS_TARGET,
427 "/proc/cmdline");
5e398e54
TG
428}
429
9f103625
TH
430static int add_usr_mount(void) {
431 _cleanup_free_ char *what = NULL;
432 const char *opts;
433
434 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
435 return 0;
436
437 if (arg_root_what && !arg_usr_what) {
438 arg_usr_what = strdup(arg_root_what);
439
440 if (!arg_usr_what)
441 return log_oom();
442 }
443
444 if (arg_root_fstype && !arg_usr_fstype) {
445 arg_usr_fstype = strdup(arg_root_fstype);
446
447 if (!arg_usr_fstype)
448 return log_oom();
449 }
450
451 if (arg_root_options && !arg_usr_options) {
452 arg_usr_options = strdup(arg_root_options);
453
454 if (!arg_usr_options)
455 return log_oom();
456 }
457
eb580002 458 if (!arg_usr_what)
9f103625
TH
459 return 0;
460
461 what = fstab_node_to_udev_node(arg_usr_what);
462 if (!path_is_absolute(what)) {
463 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
464 return -1;
465 }
466
eb580002
MM
467 if (!arg_usr_options)
468 opts = arg_root_rw > 0 ? "rw" : "ro";
d15d0333 469 else if (!fstab_test_option(arg_usr_options, "ro\0" "rw\0"))
63c372cb 470 opts = strjoina(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro");
eb580002
MM
471 else
472 opts = arg_usr_options;
9f103625
TH
473
474 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
475 return add_mount(what,
476 "/sysroot/usr",
477 arg_usr_fstype,
478 opts,
479 1,
480 false,
481 false,
482 false,
483 SPECIAL_INITRD_ROOT_FS_TARGET,
484 "/proc/cmdline");
485}
486
059cb385 487static int parse_proc_cmdline_item(const char *key, const char *value) {
74df0fca 488 int r;
94734142 489
9f103625
TH
490 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
491 * instance should take precedence. In the case of multiple rootflags=
492 * or usrflags= the arguments should be concatenated */
6db615c1 493
059cb385 494 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
e48fdd84 495
059cb385 496 r = parse_boolean(value);
141a79f4 497 if (r < 0)
059cb385 498 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
141a79f4 499 else
e48fdd84 500 arg_fstab_enabled = r;
94734142 501
6db615c1
LP
502 } else if (streq(key, "root") && value) {
503
f88dc3ed 504 if (free_and_strdup(&arg_root_what, value) < 0)
6db615c1
LP
505 return log_oom();
506
507 } else if (streq(key, "rootfstype") && value) {
508
f88dc3ed 509 if (free_and_strdup(&arg_root_fstype, value) < 0)
6db615c1
LP
510 return log_oom();
511
512 } else if (streq(key, "rootflags") && value) {
513 char *o;
514
515 o = arg_root_options ?
516 strjoin(arg_root_options, ",", value, NULL) :
517 strdup(value);
518 if (!o)
519 return log_oom();
520
521 free(arg_root_options);
522 arg_root_options = o;
523
9f103625
TH
524 } else if (streq(key, "mount.usr") && value) {
525
526 if (free_and_strdup(&arg_usr_what, value) < 0)
527 return log_oom();
528
529 } else if (streq(key, "mount.usrfstype") && value) {
530
531 if (free_and_strdup(&arg_usr_fstype, value) < 0)
532 return log_oom();
533
534 } else if (streq(key, "mount.usrflags") && value) {
535 char *o;
536
537 o = arg_usr_options ?
538 strjoin(arg_usr_options, ",", value, NULL) :
539 strdup(value);
540 if (!o)
541 return log_oom();
542
543 free(arg_usr_options);
544 arg_usr_options = o;
545
6db615c1
LP
546 } else if (streq(key, "rw") && !value)
547 arg_root_rw = true;
548 else if (streq(key, "ro") && !value)
549 arg_root_rw = false;
94734142 550
d0aa9ce5 551 return 0;
94734142
LP
552}
553
6b1dc2bd 554int main(int argc, char *argv[]) {
e48fdd84 555 int r = 0;
6b1dc2bd 556
07719a21
LP
557 if (argc > 1 && argc != 4) {
558 log_error("This program takes three or no arguments.");
6b1dc2bd
LP
559 return EXIT_FAILURE;
560 }
561
562 if (argc > 1)
563 arg_dest = argv[1];
564
a6903061 565 log_set_target(LOG_TARGET_SAFE);
6b1dc2bd
LP
566 log_parse_environment();
567 log_open();
568
6b1dc2bd
LP
569 umask(0022);
570
b5884878
LP
571 r = parse_proc_cmdline(parse_proc_cmdline_item);
572 if (r < 0)
da927ba9 573 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
94734142 574
9f103625
TH
575 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
576 if (in_initrd()) {
6db615c1 577 r = add_root_mount();
9f103625
TH
578 if (r == 0)
579 r = add_usr_mount();
580 }
5e398e54 581
e48fdd84
LP
582 /* Honour /etc/fstab only when that's enabled */
583 if (arg_fstab_enabled) {
584 int k;
ac4785b0 585
75a59316
ZJS
586 log_debug("Parsing /etc/fstab");
587
e48fdd84
LP
588 /* Parse the local /etc/fstab, possibly from the initrd */
589 k = parse_fstab(false);
590 if (k < 0)
591 r = k;
ac4785b0 592
e48fdd84
LP
593 /* If running in the initrd also parse the /etc/fstab from the host */
594 if (in_initrd()) {
75a59316
ZJS
595 log_debug("Parsing /sysroot/etc/fstab");
596
e48fdd84
LP
597 k = parse_fstab(true);
598 if (k < 0)
599 r = k;
600 }
601 }
6b1dc2bd 602
126cc760 603 free(arg_root_what);
59cfa62f
LP
604 free(arg_root_fstype);
605 free(arg_root_options);
606
607 free(arg_usr_what);
608 free(arg_usr_fstype);
609 free(arg_usr_options);
126cc760 610
e48fdd84 611 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
6b1dc2bd 612}