1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
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.
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.
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/>.
30 #include "unit-name.h"
31 #include "path-util.h"
32 #include "mount-setup.h"
38 static const char *arg_dest
= "/tmp";
39 static bool arg_enabled
= true;
41 static int device_name(const char *path
, char **unit
) {
46 if (!is_device_path(path
))
49 p
= unit_name_from_path(path
, ".device");
57 static int mount_find_pri(struct mntent
*me
, int *ret
) {
64 pri
= hasmntopt(me
, "pri");
71 r
= strtoul(pri
, &end
, 10);
75 if (end
== pri
|| (*end
!= ',' && *end
!= 0))
82 static int add_swap(const char *what
, struct mntent
*me
) {
83 char _cleanup_free_
*name
= NULL
, *unit
= NULL
, *lnk
= NULL
, *device
= NULL
;
84 FILE _cleanup_fclose_
*f
= NULL
;
91 r
= mount_find_pri(me
, &pri
);
93 log_error("Failed to parse priority");
97 noauto
= !!hasmntopt(me
, "noauto");
98 nofail
= !!hasmntopt(me
, "nofail");
100 name
= unit_name_from_path(what
, ".swap");
104 unit
= strjoin(arg_dest
, "/", name
, NULL
);
108 f
= fopen(unit
, "wxe");
111 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit
);
113 log_error("Failed to create unit file %s: %m", unit
);
117 fputs("# Automatically generated by systemd-fstab-generator\n\n"
119 "SourcePath=/etc/fstab\n"
120 "DefaultDependencies=no\n"
121 "Conflicts=" SPECIAL_UMOUNT_TARGET
"\n"
122 "Before=" SPECIAL_UMOUNT_TARGET
"\n", f
);
124 if (!noauto
&& !nofail
)
125 fputs("Before=" SPECIAL_SWAP_TARGET
"\n", f
);
140 log_error("Failed to write unit file %s: %m", unit
);
145 lnk
= strjoin(arg_dest
, "/" SPECIAL_SWAP_TARGET
".wants/", name
, NULL
);
149 mkdir_parents_label(lnk
, 0755);
150 if (symlink(unit
, lnk
) < 0) {
151 log_error("Failed to create symlink %s: %m", lnk
);
155 r
= device_name(what
, &device
);
161 lnk
= strjoin(arg_dest
, "/", device
, ".wants/", name
, NULL
);
165 mkdir_parents_label(lnk
, 0755);
166 if (symlink(unit
, lnk
) < 0) {
167 log_error("Failed to create symlink %s: %m", lnk
);
176 static bool mount_is_bind(struct mntent
*me
) {
180 hasmntopt(me
, "bind") ||
181 streq(me
->mnt_type
, "bind") ||
182 hasmntopt(me
, "rbind") ||
183 streq(me
->mnt_type
, "rbind");
186 static bool mount_is_network(struct mntent
*me
) {
190 hasmntopt(me
, "_netdev") ||
191 fstype_is_network(me
->mnt_type
);
194 static bool mount_in_initrd(struct mntent
*me
) {
198 hasmntopt(me
, "x-initrd.mount") ||
199 streq(me
->mnt_dir
, "/usr");
202 static int add_mount(
215 const char *source
) {
217 *name
= NULL
, *unit
= NULL
, *lnk
= NULL
, *device
= NULL
,
218 *automount_name
= NULL
, *automount_unit
= NULL
;
219 FILE _cleanup_fclose_
*f
= NULL
;
228 if (streq(type
, "autofs"))
231 if (!is_path(where
)) {
232 log_warning("Mount point %s is not a valid path, ignoring.", where
);
236 if (mount_point_is_api(where
) ||
237 mount_point_ignore(where
))
240 name
= unit_name_from_path(where
, ".mount");
244 unit
= strjoin(arg_dest
, "/", name
, NULL
);
248 f
= fopen(unit
, "wxe");
251 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit
);
253 log_error("Failed to create unit file %s: %m", unit
);
258 "# Automatically generated by systemd-fstab-generator\n\n"
261 "DefaultDependencies=no\n",
264 if (!path_equal(where
, "/")) {
276 "Conflicts=" SPECIAL_UMOUNT_TARGET
"\n"
277 "Before=" SPECIAL_UMOUNT_TARGET
"\n");
280 if (post
&& !noauto
&& !nofail
&& !automount
)
297 if (!isempty(opts
) &&
298 !streq(opts
, "defaults"))
305 log_error("Failed to write unit file %s: %m", unit
);
311 lnk
= strjoin(arg_dest
, "/", post
, nofail
|| automount
? ".wants/" : ".requires/", name
, NULL
);
315 mkdir_parents_label(lnk
, 0755);
316 if (symlink(unit
, lnk
) < 0) {
317 log_error("Failed to create symlink %s: %m", lnk
);
323 !path_equal(where
, "/")) {
325 r
= device_name(what
, &device
);
331 lnk
= strjoin(arg_dest
, "/", device
, ".wants/", name
, NULL
);
335 mkdir_parents_label(lnk
, 0755);
336 if (symlink(unit
, lnk
) < 0) {
337 log_error("Failed to create symlink %s: %m", lnk
);
344 if (automount
&& !path_equal(where
, "/")) {
345 automount_name
= unit_name_from_path(where
, ".automount");
349 automount_unit
= strjoin(arg_dest
, "/", automount_name
, NULL
);
354 f
= fopen(automount_unit
, "wxe");
356 log_error("Failed to create unit file %s: %m", automount_unit
);
361 "# Automatically generated by systemd-fstab-generator\n\n"
364 "DefaultDependencies=no\n"
365 "Conflicts=" SPECIAL_UMOUNT_TARGET
"\n"
366 "Before=" SPECIAL_UMOUNT_TARGET
"\n",
381 log_error("Failed to write unit file %s: %m", automount_unit
);
386 lnk
= strjoin(arg_dest
, "/", post
, nofail
? ".wants/" : ".requires/", automount_name
, NULL
);
390 mkdir_parents_label(lnk
, 0755);
391 if (symlink(automount_unit
, lnk
) < 0) {
392 log_error("Failed to create symlink %s: %m", lnk
);
400 static int parse_fstab(const char *prefix
, bool initrd
) {
401 _cleanup_free_
char *fstab_path
= NULL
;
406 fstab_path
= strjoin(strempty(prefix
), "/etc/fstab", NULL
);
410 f
= setmntent(fstab_path
, "r");
415 log_error("Failed to open %s/etc/fstab: %m", strempty(prefix
));
419 while ((me
= getmntent(f
))) {
420 char _cleanup_free_
*where
= NULL
, *what
= NULL
;
423 if (initrd
&& !mount_in_initrd(me
))
426 what
= fstab_node_to_udev_node(me
->mnt_fsname
);
427 where
= strjoin(strempty(prefix
), me
->mnt_dir
, NULL
);
428 if (!what
|| !where
) {
434 path_kill_slashes(where
);
436 log_debug("Found entry what=%s where=%s type=%s", what
, where
, me
->mnt_type
);
438 if (streq(me
->mnt_type
, "swap"))
439 k
= add_swap(what
, me
);
441 bool noauto
, nofail
, automount
, isbind
;
442 const char *pre
, *post
, *setup
;
444 noauto
= !!hasmntopt(me
, "noauto");
445 nofail
= !!hasmntopt(me
, "nofail");
447 hasmntopt(me
, "comment=systemd.automount") ||
448 hasmntopt(me
, "x-systemd.automount");
449 isbind
= mount_is_bind(me
);
452 post
= SPECIAL_INITRD_FS_TARGET
;
455 } else if (mount_in_initrd(me
)) {
456 post
= SPECIAL_INITRD_ROOT_FS_TARGET
;
459 } else if (mount_is_network(me
)) {
460 post
= SPECIAL_REMOTE_FS_TARGET
;
461 pre
= SPECIAL_REMOTE_FS_PRE_TARGET
;
462 setup
= SPECIAL_REMOTE_FS_SETUP_TARGET
;
464 post
= SPECIAL_LOCAL_FS_TARGET
;
465 pre
= SPECIAL_LOCAL_FS_PRE_TARGET
;
469 k
= add_mount(what
, where
, me
->mnt_type
, me
->mnt_opts
,
470 me
->mnt_passno
, noauto
, nofail
, automount
,
471 isbind
, pre
, post
, setup
, fstab_path
);
483 static int parse_new_root_from_proc_cmdline(void) {
484 _cleanup_free_
char *what
= NULL
, *type
= NULL
, *opts
= NULL
, *line
= NULL
;
489 r
= read_one_line_file("/proc/cmdline", &line
);
491 log_error("Failed to read /proc/cmdline, ignoring: %s", strerror(-r
));
496 type
= strdup("auto");
500 /* root= and roofstype= may occur more than once, the last instance should take precedence.
501 * In the case of multiple rootflags= the arguments should be concatenated */
502 FOREACH_WORD_QUOTED(w
, l
, line
, state
) {
503 _cleanup_free_
char *word
;
505 word
= strndup(w
, l
);
509 else if (startswith(word
, "root=")) {
511 what
= fstab_node_to_udev_node(word
+5);
515 } else if (startswith(word
, "rootfstype=")) {
517 type
= strdup(word
+ 11);
521 } else if (startswith(word
, "rootflags=")) {
524 o
= strjoin(opts
, ",", word
+ 10, NULL
);
531 } else if (streq(word
, "ro") || streq(word
, "rw")) {
534 o
= strjoin(opts
, ",", word
, NULL
);
544 log_debug("Could not find a root= entry on the kernel commandline.");
548 if (what
[0] != '/') {
549 log_debug("Skipping entry what=%s where=/sysroot type=%s", what
, type
);
553 log_debug("Found entry what=%s where=/sysroot type=%s", what
, type
);
554 r
= add_mount(what
, "/sysroot", type
, opts
, 0, false, false, false,
555 false, NULL
, SPECIAL_INITRD_ROOT_FS_TARGET
, NULL
, "/proc/cmdline");
557 return (r
< 0) ? r
: 0;
560 static int parse_proc_cmdline(void) {
561 char _cleanup_free_
*line
= NULL
;
566 if (detect_container(NULL
) > 0)
569 r
= read_one_line_file("/proc/cmdline", &line
);
571 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r
));
575 FOREACH_WORD_QUOTED(w
, l
, line
, state
) {
576 char _cleanup_free_
*word
= NULL
;
578 word
= strndup(w
, l
);
582 if (startswith(word
, "fstab=")) {
583 r
= parse_boolean(word
+ 6);
585 log_warning("Failed to parse fstab switch %s. Ignoring.", word
+ 6);
589 } else if (startswith(word
, "rd.fstab=")) {
592 r
= parse_boolean(word
+ 6);
594 log_warning("Failed to parse fstab switch %s. Ignoring.", word
+ 6);
599 } else if (startswith(word
, "fstab.") ||
600 (in_initrd() && startswith(word
, "rd.fstab."))) {
602 log_warning("Unknown kernel switch %s. Ignoring.", word
);
609 int main(int argc
, char *argv
[]) {
612 if (argc
> 1 && argc
!= 4) {
613 log_error("This program takes three or no arguments.");
620 log_set_target(LOG_TARGET_SAFE
);
621 log_parse_environment();
626 if (parse_proc_cmdline() < 0)
630 r
= parse_new_root_from_proc_cmdline();
633 return (r
< 0) ? EXIT_FAILURE
: EXIT_SUCCESS
;
635 k
= parse_fstab(NULL
, false);
638 l
= parse_fstab("/sysroot", true);
640 return (r
< 0) || (k
< 0) || (l
< 0) ? EXIT_FAILURE
: EXIT_SUCCESS
;