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 mount_find_pri(struct mntent
*me
, int *ret
) {
48 pri
= hasmntopt(me
, "pri");
55 r
= strtoul(pri
, &end
, 10);
59 if (end
== pri
|| (*end
!= ',' && *end
!= 0))
66 static int add_swap(const char *what
, struct mntent
*me
) {
67 _cleanup_free_
char *name
= NULL
, *unit
= NULL
, *lnk
= NULL
;
68 _cleanup_fclose_
FILE *f
= NULL
;
75 r
= mount_find_pri(me
, &pri
);
77 log_error("Failed to parse priority");
81 noauto
= !!hasmntopt(me
, "noauto");
83 name
= unit_name_from_path(what
, ".swap");
87 unit
= strjoin(arg_dest
, "/", name
, NULL
);
91 f
= fopen(unit
, "wxe");
94 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit
);
96 log_error("Failed to create unit file %s: %m", unit
);
101 "# Automatically generated by systemd-fstab-generator\n\n"
103 "SourcePath=/etc/fstab\n\n"
115 log_error("Failed to write unit file %s: %m", unit
);
120 lnk
= strjoin(arg_dest
, "/" SPECIAL_SWAP_TARGET
".wants/", name
, NULL
);
124 mkdir_parents_label(lnk
, 0755);
125 if (symlink(unit
, lnk
) < 0) {
126 log_error("Failed to create symlink %s: %m", lnk
);
134 static bool mount_is_network(struct mntent
*me
) {
138 hasmntopt(me
, "_netdev") ||
139 fstype_is_network(me
->mnt_type
);
142 static bool mount_in_initrd(struct mntent
*me
) {
146 hasmntopt(me
, "x-initrd.mount") ||
147 streq(me
->mnt_dir
, "/usr");
150 static int add_mount(
160 const char *source
) {
162 *name
= NULL
, *unit
= NULL
, *lnk
= NULL
,
163 *automount_name
= NULL
, *automount_unit
= NULL
;
164 _cleanup_fclose_
FILE *f
= NULL
;
172 if (streq(type
, "autofs"))
175 if (!is_path(where
)) {
176 log_warning("Mount point %s is not a valid path, ignoring.", where
);
180 if (mount_point_is_api(where
) ||
181 mount_point_ignore(where
))
184 name
= unit_name_from_path(where
, ".mount");
188 unit
= strjoin(arg_dest
, "/", name
, NULL
);
192 f
= fopen(unit
, "wxe");
195 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit
);
197 log_error("Failed to create unit file %s: %m", unit
);
202 "# Automatically generated by systemd-fstab-generator\n\n"
207 if (post
&& !noauto
&& !nofail
&& !automount
)
224 if (!isempty(opts
) &&
225 !streq(opts
, "defaults"))
232 log_error("Failed to write unit file %s: %m", unit
);
238 lnk
= strjoin(arg_dest
, "/", post
, nofail
|| automount
? ".wants/" : ".requires/", name
, NULL
);
242 mkdir_parents_label(lnk
, 0755);
243 if (symlink(unit
, lnk
) < 0) {
244 log_error("Failed to create symlink %s: %m", lnk
);
250 if (automount
&& !path_equal(where
, "/")) {
251 automount_name
= unit_name_from_path(where
, ".automount");
255 automount_unit
= strjoin(arg_dest
, "/", automount_name
, NULL
);
260 f
= fopen(automount_unit
, "wxe");
262 log_error("Failed to create unit file %s: %m", automount_unit
);
267 "# Automatically generated by systemd-fstab-generator\n\n"
284 log_error("Failed to write unit file %s: %m", automount_unit
);
289 lnk
= strjoin(arg_dest
, "/", post
, nofail
? ".wants/" : ".requires/", automount_name
, NULL
);
293 mkdir_parents_label(lnk
, 0755);
294 if (symlink(automount_unit
, lnk
) < 0) {
295 log_error("Failed to create symlink %s: %m", lnk
);
303 static int parse_fstab(const char *prefix
, bool initrd
) {
304 _cleanup_free_
char *fstab_path
= NULL
;
309 fstab_path
= strjoin(strempty(prefix
), "/etc/fstab", NULL
);
313 f
= setmntent(fstab_path
, "r");
318 log_error("Failed to open %s/etc/fstab: %m", strempty(prefix
));
322 while ((me
= getmntent(f
))) {
323 _cleanup_free_
char *where
= NULL
, *what
= NULL
;
326 if (initrd
&& !mount_in_initrd(me
))
329 what
= fstab_node_to_udev_node(me
->mnt_fsname
);
330 where
= strjoin(strempty(prefix
), me
->mnt_dir
, NULL
);
331 if (!what
|| !where
) {
337 path_kill_slashes(where
);
339 log_debug("Found entry what=%s where=%s type=%s", what
, where
, me
->mnt_type
);
341 if (streq(me
->mnt_type
, "swap"))
342 k
= add_swap(what
, me
);
344 bool noauto
, nofail
, automount
;
347 noauto
= !!hasmntopt(me
, "noauto");
348 nofail
= !!hasmntopt(me
, "nofail");
350 hasmntopt(me
, "comment=systemd.automount") ||
351 hasmntopt(me
, "x-systemd.automount");
354 post
= SPECIAL_INITRD_FS_TARGET
;
355 } else if (mount_in_initrd(me
)) {
356 post
= SPECIAL_INITRD_ROOT_FS_TARGET
;
357 } else if (mount_is_network(me
)) {
358 post
= SPECIAL_REMOTE_FS_TARGET
;
360 post
= SPECIAL_LOCAL_FS_TARGET
;
363 k
= add_mount(what
, where
, me
->mnt_type
, me
->mnt_opts
,
364 me
->mnt_passno
, noauto
, nofail
, automount
,
377 static int parse_new_root_from_proc_cmdline(void) {
378 _cleanup_free_
char *what
= NULL
, *type
= NULL
, *opts
= NULL
, *line
= NULL
;
384 r
= read_one_line_file("/proc/cmdline", &line
);
386 log_error("Failed to read /proc/cmdline, ignoring: %s", strerror(-r
));
391 type
= strdup("auto");
395 /* root= and roofstype= may occur more than once, the last instance should take precedence.
396 * In the case of multiple rootflags= the arguments should be concatenated */
397 FOREACH_WORD_QUOTED(w
, l
, line
, state
) {
398 _cleanup_free_
char *word
;
400 word
= strndup(w
, l
);
404 else if (startswith(word
, "root=")) {
406 what
= fstab_node_to_udev_node(word
+5);
410 } else if (startswith(word
, "rootfstype=")) {
412 type
= strdup(word
+ 11);
416 } else if (startswith(word
, "rootflags=")) {
419 o
= strjoin(opts
, ",", word
+ 10, NULL
);
426 } else if (streq(word
, "ro") || streq(word
, "rw")) {
429 o
= strjoin(opts
, ",", word
, NULL
);
438 noauto
= !!strstr(opts
, "noauto");
439 nofail
= !!strstr(opts
, "nofail");
442 log_debug("Could not find a root= entry on the kernel commandline.");
446 if (what
[0] != '/') {
447 log_debug("Skipping entry what=%s where=/sysroot type=%s", what
, type
);
451 log_debug("Found entry what=%s where=/sysroot type=%s", what
, type
);
452 r
= add_mount(what
, "/sysroot", type
, opts
, 0, noauto
, nofail
, false,
453 SPECIAL_INITRD_ROOT_FS_TARGET
, "/proc/cmdline");
455 return (r
< 0) ? r
: 0;
458 static int parse_proc_cmdline(void) {
459 _cleanup_free_
char *line
= NULL
;
464 if (detect_container(NULL
) > 0)
467 r
= read_one_line_file("/proc/cmdline", &line
);
469 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r
));
473 FOREACH_WORD_QUOTED(w
, l
, line
, state
) {
474 _cleanup_free_
char *word
= NULL
;
476 word
= strndup(w
, l
);
480 if (startswith(word
, "fstab=")) {
481 r
= parse_boolean(word
+ 6);
483 log_warning("Failed to parse fstab switch %s. Ignoring.", word
+ 6);
487 } else if (startswith(word
, "rd.fstab=")) {
490 r
= parse_boolean(word
+ 9);
492 log_warning("Failed to parse fstab switch %s. Ignoring.", word
+ 9);
497 } else if (startswith(word
, "fstab.") ||
498 (in_initrd() && startswith(word
, "rd.fstab."))) {
500 log_warning("Unknown kernel switch %s. Ignoring.", word
);
507 int main(int argc
, char *argv
[]) {
510 if (argc
> 1 && argc
!= 4) {
511 log_error("This program takes three or no arguments.");
518 log_set_target(LOG_TARGET_SAFE
);
519 log_parse_environment();
524 if (parse_proc_cmdline() < 0)
528 r
= parse_new_root_from_proc_cmdline();
531 return (r
< 0) ? EXIT_FAILURE
: EXIT_SUCCESS
;
533 k
= parse_fstab(NULL
, false);
536 l
= parse_fstab("/sysroot", true);
538 return (r
< 0) || (k
< 0) || (l
< 0) ? EXIT_FAILURE
: EXIT_SUCCESS
;