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");
114 log_error("Failed to create unit file %s: %m", unit);
118 fputs("# Automatically generated by systemd-fstab-generator\n\n"
120 "SourcePath=/etc/fstab\n"
121 "DefaultDependencies=no\n"
122 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
123 "Before=" SPECIAL_UMOUNT_TARGET "\n", f);
125 if (!noauto && !nofail)
126 fputs("Before=" SPECIAL_SWAP_TARGET "\n", f);
141 log_error("Failed to write unit file %s: %m", unit);
147 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
153 mkdir_parents_label(lnk, 0755);
154 if (symlink(unit, lnk) < 0) {
155 log_error("Failed to create symlink %s: %m", lnk);
160 r = device_name(what, &device);
166 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
172 mkdir_parents_label(lnk, 0755);
173 if (symlink(unit, lnk) < 0) {
174 log_error("Failed to create symlink %s: %m", lnk);
194 static bool mount_is_network(struct mntent *me) {
198 hasmntopt(me, "_netdev") ||
199 fstype_is_network(me->mnt_type);
202 static int add_mount(const char *what, const char *where, struct mntent *me) {
203 char *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL, *automount_name = NULL, *automount_unit = NULL;
205 bool noauto, nofail, automount, isbind, isnetwork;
207 const char *post, *pre;
213 if (streq(me->mnt_type, "autofs"))
216 if (!is_path(where)) {
217 log_warning("Mount point %s is not a valid path, ignoring.", where);
221 if (mount_point_is_api(where) ||
222 mount_point_ignore(where))
225 isnetwork = mount_is_network(me);
226 isbind = !!hasmntopt(me, "bind");
228 noauto = !!hasmntopt(me, "noauto");
229 nofail = !!hasmntopt(me, "nofail");
231 hasmntopt(me, "comment=systemd.automount") ||
232 hasmntopt(me, "x-systemd.automount");
235 post = SPECIAL_REMOTE_FS_TARGET;
236 pre = SPECIAL_REMOTE_FS_PRE_TARGET;
238 post = SPECIAL_LOCAL_FS_TARGET;
239 pre = SPECIAL_LOCAL_FS_PRE_TARGET;
242 name = unit_name_from_path(where, ".mount");
248 unit = strjoin(arg_dest, "/", name, NULL);
254 f = fopen(unit, "wxe");
257 log_error("Failed to create unit file %s: %m", unit);
261 fputs("# Automatically generated by systemd-fstab-generator\n\n"
263 "SourcePath=/etc/fstab\n"
264 "DefaultDependencies=no\n", f);
266 if (!path_equal(where, "/"))
270 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
271 "Before=" SPECIAL_UMOUNT_TARGET "\n",
276 if (!noauto && !nofail && !automount)
293 if (!isempty(me->mnt_opts) &&
294 !streq(me->mnt_opts, "defaults"))
301 log_error("Failed to write unit file %s: %m", unit);
307 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
313 mkdir_parents_label(lnk, 0755);
314 if (symlink(unit, lnk) < 0) {
315 log_error("Failed to create symlink %s: %m", lnk);
321 !path_equal(where, "/")) {
323 r = device_name(what, &device);
329 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);
345 if (automount && !path_equal(where, "/")) {
346 automount_name = unit_name_from_path(where, ".automount");
352 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
353 if (!automount_unit) {
359 f = fopen(automount_unit, "wxe");
362 log_error("Failed to create unit file %s: %m", automount_unit);
367 "# Automatically generated by systemd-fstab-generator\n\n"
369 "SourcePath=/etc/fstab\n"
370 "DefaultDependencies=no\n"
371 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
372 "Before=" SPECIAL_UMOUNT_TARGET " %s\n"
381 log_error("Failed to write unit file %s: %m", automount_unit);
387 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
393 mkdir_parents_label(lnk, 0755);
394 if (symlink(automount_unit, lnk) < 0) {
395 log_error("Failed to create symlink %s: %m", lnk);
410 free(automount_name);
411 free(automount_unit);
416 static int parse_fstab(void) {
422 f = setmntent("/etc/fstab", "r");
427 log_error("Failed to open /etc/fstab: %m");
431 while ((me = getmntent(f))) {
435 what = fstab_node_to_udev_node(me->mnt_fsname);
441 where = strdup(me->mnt_dir);
449 path_kill_slashes(where);
451 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
453 if (streq(me->mnt_type, "swap"))
454 k = add_swap(what, me);
456 k = add_mount(what, where, me);
470 static int parse_proc_cmdline(void) {
471 char *line, *w, *state;
475 if (detect_container(NULL) > 0)
478 r = read_one_line_file("/proc/cmdline", &line);
480 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
484 FOREACH_WORD_QUOTED(w, l, line, state) {
487 word = strndup(w, l);
493 if (startswith(word, "fstab=")) {
494 r = parse_boolean(word + 6);
496 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
500 } else if (startswith(word, "rd.fstab=")) {
503 r = parse_boolean(word + 6);
505 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
510 } else if (startswith(word, "fstab.") ||
511 (in_initrd() && startswith(word, "rd.fstab."))) {
513 log_warning("Unknown kernel switch %s. Ignoring.", word);
526 int main(int argc, char *argv[]) {
529 if (argc > 1 && argc != 4) {
530 log_error("This program takes three or no arguments.");
537 log_set_target(LOG_TARGET_SAFE);
538 log_parse_environment();
543 if (parse_proc_cmdline() < 0)
551 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;