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 int add_mount(const char *what
, const char *where
, const char *type
, const char *opts
,
195 int passno
, bool wait
, bool noauto
, bool nofail
, bool automount
, bool isbind
, bool isnetwork
,
196 const char *source
) {
198 *name
= NULL
, *unit
= NULL
, *lnk
= NULL
, *device
= NULL
,
199 *automount_name
= NULL
, *automount_unit
= NULL
;
200 FILE _cleanup_fclose_
*f
= NULL
;
202 const char *post
, *pre
;
210 if (streq(type
, "autofs"))
213 if (!is_path(where
)) {
214 log_warning("Mount point %s is not a valid path, ignoring.", where
);
218 if (mount_point_is_api(where
) ||
219 mount_point_ignore(where
))
223 post
= SPECIAL_REMOTE_FS_TARGET
;
224 pre
= SPECIAL_REMOTE_FS_PRE_TARGET
;
226 post
= SPECIAL_LOCAL_FS_TARGET
;
227 pre
= SPECIAL_LOCAL_FS_PRE_TARGET
;
230 name
= unit_name_from_path(where
, ".mount");
234 unit
= strjoin(arg_dest
, "/", name
, NULL
);
238 f
= fopen(unit
, "wxe");
241 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit
);
243 log_error("Failed to create unit file %s: %m", unit
);
248 "# Automatically generated by systemd-fstab-generator\n\n"
251 "DefaultDependencies=no\n",
254 if (!path_equal(where
, "/"))
258 "Conflicts=" SPECIAL_UMOUNT_TARGET
"\n"
259 "Before=" SPECIAL_UMOUNT_TARGET
"\n",
264 if (!noauto
&& !nofail
&& !automount
)
281 if (!isempty(opts
) &&
282 !streq(opts
, "defaults"))
293 log_error("Failed to write unit file %s: %m", unit
);
298 lnk
= strjoin(arg_dest
, "/", post
, nofail
|| automount
? ".wants/" : ".requires/", name
, NULL
);
302 mkdir_parents_label(lnk
, 0755);
303 if (symlink(unit
, lnk
) < 0) {
304 log_error("Failed to create symlink %s: %m", lnk
);
309 !path_equal(where
, "/")) {
311 r
= device_name(what
, &device
);
317 lnk
= strjoin(arg_dest
, "/", device
, ".wants/", name
, NULL
);
321 mkdir_parents_label(lnk
, 0755);
322 if (symlink(unit
, lnk
) < 0) {
323 log_error("Failed to create symlink %s: %m", lnk
);
330 if (automount
&& !path_equal(where
, "/")) {
331 automount_name
= unit_name_from_path(where
, ".automount");
335 automount_unit
= strjoin(arg_dest
, "/", automount_name
, NULL
);
340 f
= fopen(automount_unit
, "wxe");
342 log_error("Failed to create unit file %s: %m", automount_unit
);
347 "# Automatically generated by systemd-fstab-generator\n\n"
349 "SourcePath=/etc/fstab\n"
350 "DefaultDependencies=no\n"
351 "Conflicts=" SPECIAL_UMOUNT_TARGET
"\n"
352 "Before=" SPECIAL_UMOUNT_TARGET
" %s\n"
361 log_error("Failed to write unit file %s: %m", automount_unit
);
366 lnk
= strjoin(arg_dest
, "/", post
, nofail
? ".wants/" : ".requires/", automount_name
, NULL
);
370 mkdir_parents_label(lnk
, 0755);
371 if (symlink(automount_unit
, lnk
) < 0) {
372 log_error("Failed to create symlink %s: %m", lnk
);
380 static int parse_fstab(void) {
386 f
= setmntent("/etc/fstab", "r");
391 log_error("Failed to open /etc/fstab: %m");
395 while ((me
= getmntent(f
))) {
396 char _cleanup_free_
*where
= NULL
, *what
= NULL
;
399 what
= fstab_node_to_udev_node(me
->mnt_fsname
);
400 where
= strdup(me
->mnt_dir
);
401 if (!what
|| !where
) {
407 path_kill_slashes(where
);
409 log_debug("Found entry what=%s where=%s type=%s", what
, where
, me
->mnt_type
);
411 if (streq(me
->mnt_type
, "swap"))
412 k
= add_swap(what
, me
);
414 bool noauto
, nofail
, automount
, isbind
, isnetwork
;
416 noauto
= !!hasmntopt(me
, "noauto");
417 nofail
= !!hasmntopt(me
, "nofail");
419 hasmntopt(me
, "comment=systemd.automount") ||
420 hasmntopt(me
, "x-systemd.automount");
421 isbind
= mount_is_bind(me
);
422 isnetwork
= mount_is_network(me
);
424 k
= add_mount(what
, where
, me
->mnt_type
, me
->mnt_opts
,
425 me
->mnt_passno
, false, noauto
, nofail
,
426 automount
, isbind
, isnetwork
,
439 static int parse_new_root_from_proc_cmdline(void) {
441 _cleanup_free_
char *what
= NULL
, *type
= NULL
, *opts
= NULL
, *line
= NULL
;
446 r
= read_one_line_file("/proc/cmdline", &line
);
448 log_error("Failed to read /proc/cmdline, ignoring: %s", strerror(-r
));
452 type
= strdup("auto");
456 /* root= and roofstype= may occur more than once, the last instance should take precedence.
457 * In the case of multiple rootflags= the arguments should be concatenated */
458 FOREACH_WORD_QUOTED(w
, l
, line
, state
) {
459 char *word
, *tmp_word
;
461 word
= strndup(w
, l
);
465 else if (startswith(word
, "root=")) {
467 what
= fstab_node_to_udev_node(word
+5);
471 } else if (startswith(word
, "rootfstype=")) {
473 type
= strdup(word
+ 11);
477 } else if (startswith(word
, "rootflags=")) {
479 opts
= strjoin(opts
, ",", word
+ 10, NULL
);
484 } else if (streq(word
, "ro") || streq(word
, "rw")) {
486 opts
= strjoin(opts
, ",", word
, NULL
);
491 } else if (streq(word
, "rootwait"))
499 log_debug("Found entry what=%s where=/sysroot type=%s", what
, type
);
500 r
= add_mount(what
, "/sysroot", type
, opts
, 0, wait
, false, false,
501 false, false, false, "/proc/cmdline");
506 log_error("Could not find a root= entry on the kernel commandline.");
511 static int parse_proc_cmdline(void) {
512 char _cleanup_free_
*line
= NULL
;
517 if (detect_container(NULL
) > 0)
520 r
= read_one_line_file("/proc/cmdline", &line
);
522 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r
));
526 FOREACH_WORD_QUOTED(w
, l
, line
, state
) {
527 char _cleanup_free_
*word
= NULL
;
529 word
= strndup(w
, l
);
533 if (startswith(word
, "fstab=")) {
534 r
= parse_boolean(word
+ 6);
536 log_warning("Failed to parse fstab switch %s. Ignoring.", word
+ 6);
540 } else if (startswith(word
, "rd.fstab=")) {
543 r
= parse_boolean(word
+ 6);
545 log_warning("Failed to parse fstab switch %s. Ignoring.", word
+ 6);
550 } else if (startswith(word
, "fstab.") ||
551 (in_initrd() && startswith(word
, "rd.fstab."))) {
553 log_warning("Unknown kernel switch %s. Ignoring.", word
);
560 int main(int argc
, char *argv
[]) {
563 if (argc
> 1 && argc
!= 4) {
564 log_error("This program takes three or no arguments.");
571 log_set_target(LOG_TARGET_SAFE
);
572 log_parse_environment();
577 if (parse_proc_cmdline() < 0)
581 k
= parse_new_root_from_proc_cmdline();
588 return (r
< 0) || (k
< 0) ? EXIT_FAILURE
: EXIT_SUCCESS
;