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"
37 static const char *arg_dest = "/tmp";
38 static bool arg_enabled = true;
40 static int device_name(const char *path, char **unit) {
45 if (!is_device_path(path))
48 p = unit_name_from_path(path, ".device");
56 static int mount_find_pri(struct mntent *me, int *ret) {
63 pri = hasmntopt(me, "pri");
70 r = strtoul(pri, &end, 10);
74 if (end == pri || (*end != ',' && *end != 0))
81 static int add_swap(const char *what, struct mntent *me) {
82 char *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL;
90 r = mount_find_pri(me, &pri);
92 log_error("Failed to parse priority");
96 noauto = !!hasmntopt(me, "noauto");
97 nofail = !!hasmntopt(me, "nofail");
99 name = unit_name_from_path(what, ".swap");
105 unit = strjoin(arg_dest, "/", name, NULL);
111 f = fopen(unit, "wxe");
115 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
117 log_error("Failed to create unit file %s: %m", unit);
121 fputs("# Automatically generated by systemd-fstab-generator\n\n"
123 "SourcePath=/etc/fstab\n"
124 "DefaultDependencies=no\n"
125 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
126 "Before=" SPECIAL_UMOUNT_TARGET "\n", f);
128 if (!noauto && !nofail)
129 fputs("Before=" SPECIAL_SWAP_TARGET "\n", f);
144 log_error("Failed to write unit file %s: %m", unit);
150 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
156 mkdir_parents_label(lnk, 0755);
157 if (symlink(unit, lnk) < 0) {
158 log_error("Failed to create symlink %s: %m", lnk);
163 r = device_name(what, &device);
169 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
175 mkdir_parents_label(lnk, 0755);
176 if (symlink(unit, lnk) < 0) {
177 log_error("Failed to create symlink %s: %m", lnk);
197 static bool mount_is_network(struct mntent *me) {
201 hasmntopt(me, "_netdev") ||
202 fstype_is_network(me->mnt_type);
205 static int add_mount(const char *what, const char *where, struct mntent *me) {
206 char *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL, *automount_name = NULL, *automount_unit = NULL;
208 bool noauto, nofail, automount, isbind, isnetwork;
210 const char *post, *pre;
216 if (streq(me->mnt_type, "autofs"))
219 if (!is_path(where)) {
220 log_warning("Mount point %s is not a valid path, ignoring.", where);
224 if (mount_point_is_api(where) ||
225 mount_point_ignore(where))
228 isnetwork = mount_is_network(me);
229 isbind = !!hasmntopt(me, "bind");
231 noauto = !!hasmntopt(me, "noauto");
232 nofail = !!hasmntopt(me, "nofail");
234 hasmntopt(me, "comment=systemd.automount") ||
235 hasmntopt(me, "x-systemd.automount");
238 post = SPECIAL_REMOTE_FS_TARGET;
239 pre = SPECIAL_REMOTE_FS_PRE_TARGET;
241 post = SPECIAL_LOCAL_FS_TARGET;
242 pre = SPECIAL_LOCAL_FS_PRE_TARGET;
245 name = unit_name_from_path(where, ".mount");
251 unit = strjoin(arg_dest, "/", name, NULL);
257 f = fopen(unit, "wxe");
261 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
263 log_error("Failed to create unit file %s: %m", unit);
267 fputs("# Automatically generated by systemd-fstab-generator\n\n"
269 "SourcePath=/etc/fstab\n"
270 "DefaultDependencies=no\n", f);
272 if (!path_equal(where, "/"))
276 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
277 "Before=" SPECIAL_UMOUNT_TARGET "\n",
282 if (!noauto && !nofail && !automount)
299 if (!isempty(me->mnt_opts) &&
300 !streq(me->mnt_opts, "defaults"))
307 log_error("Failed to write unit file %s: %m", unit);
313 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
319 mkdir_parents_label(lnk, 0755);
320 if (symlink(unit, lnk) < 0) {
321 log_error("Failed to create symlink %s: %m", lnk);
327 !path_equal(where, "/")) {
329 r = device_name(what, &device);
335 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
341 mkdir_parents_label(lnk, 0755);
342 if (symlink(unit, lnk) < 0) {
343 log_error("Failed to create symlink %s: %m", lnk);
351 if (automount && !path_equal(where, "/")) {
352 automount_name = unit_name_from_path(where, ".automount");
358 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
359 if (!automount_unit) {
365 f = fopen(automount_unit, "wxe");
368 log_error("Failed to create unit file %s: %m", automount_unit);
373 "# Automatically generated by systemd-fstab-generator\n\n"
375 "SourcePath=/etc/fstab\n"
376 "DefaultDependencies=no\n"
377 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
378 "Before=" SPECIAL_UMOUNT_TARGET " %s\n"
387 log_error("Failed to write unit file %s: %m", automount_unit);
393 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
399 mkdir_parents_label(lnk, 0755);
400 if (symlink(automount_unit, lnk) < 0) {
401 log_error("Failed to create symlink %s: %m", lnk);
416 free(automount_name);
417 free(automount_unit);
422 static int parse_fstab(void) {
428 f = setmntent("/etc/fstab", "r");
433 log_error("Failed to open /etc/fstab: %m");
437 while ((me = getmntent(f))) {
441 what = fstab_node_to_udev_node(me->mnt_fsname);
447 where = strdup(me->mnt_dir);
455 path_kill_slashes(where);
457 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
459 if (streq(me->mnt_type, "swap"))
460 k = add_swap(what, me);
462 k = add_mount(what, where, me);
476 static int parse_proc_cmdline(void) {
477 char *line, *w, *state;
481 if (detect_container(NULL) > 0)
484 r = read_one_line_file("/proc/cmdline", &line);
486 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
490 FOREACH_WORD_QUOTED(w, l, line, state) {
493 word = strndup(w, l);
499 if (startswith(word, "fstab=")) {
500 r = parse_boolean(word + 6);
502 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
506 } else if (startswith(word, "rd.fstab=")) {
509 r = parse_boolean(word + 6);
511 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
516 } else if (startswith(word, "fstab.") ||
517 (in_initrd() && startswith(word, "rd.fstab."))) {
519 log_warning("Unknown kernel switch %s. Ignoring.", word);
532 int main(int argc, char *argv[]) {
535 if (argc > 1 && argc != 4) {
536 log_error("This program takes three or no arguments.");
543 log_set_target(LOG_TARGET_SAFE);
544 log_parse_environment();
549 if (parse_proc_cmdline() < 0)
557 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;